3

I am following this code example found here to create a collapsible panel using css/html/javascript:

function toggleCollapsibleSectionWithAnimation() {
  this.classList.toggle("collapsible-active");
  var buttonId = this.id;
  var sectionId = buttonId.replace("button","section");
  var content = document.getElementById(sectionId);
  if (content.style.maxHeight) {
    content.style.maxHeight = null;
  } else {
    content.style.maxHeight = content.scrollHeight + "px";
  }
}
/* Style the button that is used to open and close the collapsible content */
.collapsible {
  background-color: transparent;
  color: #444;
  cursor: pointer;
  width: auto;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.collapsible-active, .collapsible:hover {
  text-decoration: underline;
}

/* Style the collapsible content. Note: hidden by default */
.collapsible-content {
  max-height: 0;
  padding: 10px;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

/* Style the collapsible content. Note: shown by default */
.collapsible-content-shown-by-default {
  max-height: 100%;
  padding: 10px;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}
<button class="collapsible" id="collapsible-button-0" onclick="toggleCollapsibleSectionWithAnimation.call(this)"><b>Model</b> (show/hide)</button>
<div class="collapsible-content" id="collapsible-section-0">
  <h1>
  content
  </h1>
</div>

This code works, by default the collapsible section will be hidden.

I wanted to reverse this so my panel is shown by default, but it should behave in the exact same way, clicking the collapsible button will toggle the section below open or closed.

Unsure on how to reverse the starting variables. When it starts hidden, we need to start with max-height of 0 on the content panel. In the javascript this is changed to content.scrollHeight to open the panel up.

Here is a JSfiddle example: https://jsfiddle.net/trbk5vwg/9/

In the JSfiddle, if you swap the div class between the "collapsible-content" and "collapsible-content-shown-by-default", you will see the toggle only works one way.

I was unsure how i would get the scrollHeight in css, and therefore unsure on how to initialize the maxHeight for the panel to be showed by default (100% didn't work).

Calvin Nunes
  • 6,376
  • 4
  • 20
  • 48
dahui
  • 2,128
  • 2
  • 21
  • 40

2 Answers2

3

Quick and easy solution:

Using the logic explained below (bottom of answer), we can solve the problem by simply adding an inline declaration of max-height to the "collapsible-content" div:

<div class="collapsible-content" id="collapsible-section-0" style="max-height: 100%">

Javascript Solution:

Working code is:

/* Style the button that is used to open and close the collapsible content */
.collapsible {
  background-color: transparent;
  color: #444;
  cursor: pointer;
  width: auto;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

/* Add a background color to the button if it is clicked on (add the .active class with JS), and when you move the mouse over it (hover) */
.collapsible-active, .collapsible:hover {
  text-decoration: underline;
}

/* Style the collapsible content. Note: hidden by default */
.collapsible-content {
  max-height: 100%;
  padding: 10px;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

/* Style the collapsible content. Note: shown by default */
.collapsible-content-shown-by-default {
  max-height: 100%;
  padding: 10px;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}
<script>
 function toggleCollapsibleSectionWithAnimation() {
  this.classList.toggle("collapsible-active");
  var buttonId = this.id;
  var sectionId = buttonId.replace("button","section");
  var content = document.getElementById(sectionId);
    var mHeight = window.getComputedStyle(content).maxHeight;
  if (mHeight !== "0px"){
    content.style.maxHeight = "0px";
  } else {
    content.style.maxHeight = "100%";
  }
 }</script>

<button class="collapsible" id="collapsible-button-0" onclick="toggleCollapsibleSectionWithAnimation.call(this)"><b>Model</b> (show/hide)</button>
<div class="collapsible-content" id="collapsible-section-0">

<h1>
content
</h1>


</div>

Why these work:

The reason you can't just change max-height to 100% in the css file: in your original JSFiddle, the first "if statement" when the button clicked is reading content.style.maxHeight. .style actually reads the inline css, which in the original case, meant it read maxHeight as null. When changing the external css (not inline) to 100%, the .style.maxHeight function still reads maxHeight as null.

To fix this in html/css, we simply need to set the initial inline css to "max-height: 100%", thus the content.style.maxHeight function will return the correct value.

To fix this in JS, we can use window.getComputedStyle(content).maxHeight, which will read the computed style (including inline and external css). Because we cannot change the computed style directly, we can then edit the inline css to override the external css originally declared (max-height: 100%). When the next "if statement" is called on the button click, the computed style will return the inline css.

Zak Avery
  • 194
  • 5
  • Great answer, thank you kindly for the samples and explanation – dahui Sep 05 '18 at 12:14
  • Thanks, and you're welcome. I actually had a face-palm moment realising I'd initially missed the simplest solution. Answer has been edited to include a much easier solution. Good luck! – Zak Avery Sep 05 '18 at 12:20
  • 1
    The other solution is a nice fix, but I like the explicitness of the javascript solution and I added that code already so I'll keep with that! – dahui Sep 05 '18 at 12:21
  • Your quick and easy solution has the problem, that the transition wont work on the first time after loading the page. I just changed the two lines in jsfiddle: `
    `
    – Darkproduct Nov 11 '19 at 13:54
1

Try this

<script>

    function toggleCollapsibleSectionWithAnimation() {
     this.classList.toggle("collapsible-active");

        var buttonId = this.id;
        var sectionId = buttonId.replace("button","section");
        var content = document.getElementById(sectionId);

        var isDefaultMode = content.classList.contains('collapsible-content-shown-by-default');

    if (isDefaultMode) {
      content.classList.remove("collapsible-content-shown-by-default");
      content.style.maxHeight = 0;
    }

        if (content.style.maxHeight) {
          content.style.maxHeight = null;
        } else {
          content.style.maxHeight = content.scrollHeight + "px";
        }
    }</script>

<button class="collapsible collapsible-active" id="collapsible-button-0" onclick="toggleCollapsibleSectionWithAnimation.call(this)"><b>Model</b> (show/hide)</button>
<div class="collapsible-content collapsible-content-shown-by-default" id="collapsible-section-0">

<h1>
content
</h1>


</div>

I have set it as essentially in the mode of post click.

PKCS12
  • 407
  • 15
  • 41