html nested collapse no bootstrap, jquery

Viewed 550

I'm trying to do a nested collapse. I saw this from webschool. As you can see nested collapse is inside it. But when it is inside it won't expand. I'm going to do a nested collapse inside nested collapse inside nested collapse (3 or 4 times eventually)

If you guys know a better way you do not have to follow the code below Thanks.

No bootstrap please and no jQuery only pure html/css vanilla js

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.collapsible {
  background-color: #777;
  color: white;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

.active, .collapsible:hover {
  background-color: #555;
}

.collapsible:after {
  content: '\002B';
  color: white;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

.active:after {
  content: "\2212";
}

.content {
  padding: 0 18px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
  background-color: #f1f1f1;
}
</style>
</head>
<body>

<h2>Animated Collapsibles</h2>

<p>A Collapsible:</p>
<button class="collapsible">Open Collapsible</button>
<div class="content">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  <button class="collapsible">Open Section 1</button>
  <div class="content">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
</div>

<p>Collapsible Set:</p>


<button class="collapsible">Open Section 3</button>
<div class="content">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  <button class="collapsible">Open Section 2</button>
  <div class="content">
    <p>test ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
</div>

<script>
var coll = document.getElementsByClassName("collapsible");
var i;

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.maxHeight){
      content.style.maxHeight = null;
    } else {
      content.style.maxHeight = content.scrollHeight + "px";
    } 
  });
}
</script>

</body>
</html>

3 Answers

You can simple set your content max-height to 350px (or what you like depending on the text content you have) instead of using content.scrollHeight

The reason it was not working is that you are setting the maxHeight to your parent but not its child element.

This will work for every other collapsible you add as well.

Run snippet below to see it working nicely.

var coll = document.getElementsByClassName("collapsible");
for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.maxHeight) {
      content.style.maxHeight = null
    } else {
      content.style.maxHeight = "350px";
    }
  });
}
.collapsible {
  background-color: #777;
  color: white;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

.active,
.collapsible:hover {
  background-color: #555;
}

.collapsible:after {
  content: '\002B';
  color: white;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

.active:after {
  content: "\2212";
}

.content {
  padding: 0 18px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
  background-color: #f1f1f1;
}
<body>
  <h2>Animated Collapsibles</h2>

  <p>A Collapsible:</p>
  <button class="collapsible">Open Collapsible</button>
  <div class="content">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    <button class="collapsible">Open Section 1</button>
    <div class="content">
      <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    </div>
  </div>

  <p>Collapsible Set:</p>
  <button class="collapsible">Open Section 3</button>
  <div class="content">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    <button class="collapsible">Open Section 2</button>
    <div class="content">
      <p>test ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
    </div>
  </div>

You internal expandable field is expanding but is blocked by the surrounding maxheight of its parent.

One way would be to include all the containing contents heights when expanding the parent. Else you could add to it for the parent when expanding the child.

Ill show the first option below.

<!DOCTYPE html>
<html>
<head>
<meta name="viewport" content="width=device-width, initial-scale=1">
<style>
.collapsible {
  background-color: #777;
  color: white;
  cursor: pointer;
  padding: 18px;
  width: 100%;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

.active, .collapsible:hover {
  background-color: #555;
}

.collapsible:after {
  content: '\002B';
  color: white;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

.active:after {
  content: "\2212";
}

.content {
  padding: 0 18px;
  max-height: 0;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
  background-color: #f1f1f1;
}
</style>
</head>
<body>

<h2>Animated Collapsibles</h2>

<p>A Collapsible:</p>
<button class="collapsible">Open Collapsible</button>
<div class="content">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  <button class="collapsible">Open Section 1</button>
  <div class="content">
    <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
</div>

<p>Collapsible Set:</p>


<button class="collapsible">Open Section 3</button>
<div class="content">
  <p>Lorem ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  <button class="collapsible">Open Section 2</button>
  <div class="content">
    <p>test ipsum dolor sit amet, consectetur adipisicing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo consequat.</p>
  </div>
</div>

<script>
var coll = document.getElementsByClassName("collapsible");
var i;

for (i = 0; i < coll.length; i++) {
  coll[i].addEventListener("click", function() {
    this.classList.toggle("active");
    var content = this.nextElementSibling;
    if (content.style.maxHeight){
      content.style.maxHeight = null;
    } else {
      var childrensHeight = Array.from(content.querySelectorAll(".content")).reduce((accumulator, currentValue) => accumulator + currentValue.scrollHeight , 0);
      content.style.maxHeight = (content.scrollHeight + childrensHeight)+ "px";
    } 
  });
}
</script>

</body>
</html>

Without JS - fade animation, thanks to Josh Brody.

Height transition is not possible with <details> (view notes).

details .collapsible {
  background-color: #777;
  color: white;
  cursor: pointer;
  padding: 18px;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

details > summary::-webkit-details-marker
{
  display: none;
}

details .collapsible:after {
  content: '\002B';
  color: white;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

details[open] > .collapsible:after {
  content: "\2212";
}

details[open] > .collapsible,
.collapsible:hover {
  background-color: #555;
}

details .content {
  padding: 18px;
  background-color: #f1f1f1;
  border: 1px solid #CCC;
  border-top: 0;
}

details[open] .content {
  animation: fade .2s ease-out;
}

@keyframes fade {
  0% {
    opacity: 0;
  }
  100% {
    opacity: 1;
  }
}
<h2>JS-Free Collapsibles - inspired by josh-brody!</h2>

<details>
  <summary class="collapsible">Collapsible A</summary>
  <div class="content">
    Some<br />
    Text<br />
    Here.<br />
    <br />
    
    <details>
      <summary class="collapsible">Collapsible B</summary>
      <div class="content">
          Read<br />
          My<br />
          Content!
      </div>
    </details>
    
  </div>
</details>

Without JS - height transition

Good thing here is, you can place the <label> elements wherever you want, in case you want to trigger a collapse from elsewhere. You will have to take care of the ids though.

.collapsible {
  display: inline-block;
  width: 100%;
}

.collapsible label {
  background-color: #777;
  color: white;
  cursor: pointer;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
  padding: 18px;
  display: block;
}

.collapsible>label::after {
  content: '\002B';
  color: white;
  font-weight: bold;
  float: right;
  margin-left: 5px;
}

.collapsible>input {
  display: none;
}

.collapsible>input:checked~label::after {
  content: "\2212";
}

.collapsible>input:checked~label,
.collapsible:hover>label {
  background-color: #555;
}

.collapsible .content {
  padding: 0 18px;
  background-color: #f1f1f1;
  border: 1px solid #CCC;
  border-top: 0;
  transition: all .2s ease-out;
  clip-path: inset(0 0 100% 0);
  height: 0px;
  overflow: hidden;
  display: block;
}

input:checked~.content {
  padding: 18px;
  height: auto;
  clip-path: inset(0 0 0 0);
}
<h2>JS-Free Animated Collapsibles</h2>

<div class="collapsible">
  <input id="collapsible-a" type="checkbox" />

  <label for="collapsible-a">
    Collapsible A
  </label>

  <div class="content">
    Some<br /> Text
    <br /> Here.
    <br />
    <br />

    <div class="collapsible">
      <input id="collapsible-b" type="checkbox" />

      <label for="collapsible-b">
        Collapsible B
      </label>

      <div class="content">
        Read<br /> My
        <br /> Content!
      </div>
    </div>
    
  </div>
</div>

Some Text

Related