Javascript collapsible panel that is initially expanded

I found this code example here and decided to implement 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>

By default, the collapsible section is hidden using this code.

I wanted to have the panel displayed by default while still maintaining the toggling behavior when clicking the collapsible button.

I was struggling with reversing the starting variables to achieve this effect. I needed the content panel to start with a max-height of 0 when hidden, but initializing it to 100% did not work as expected.

In this JSfiddle example: https://jsfiddle.net/trbk5vwg/9/, switching the div classes between "collapsible-content" and "collapsible-content-shown-by-default" shows that the toggle only works one way.

I couldn't figure out how to get the scrollHeight in CSS and thus was unsure about setting the maxHeight for the panel to be shown by default.

Answer №1

Simple Solution:

To quickly solve the issue at hand, we can add a max-height inline declaration to the "collapsible-content" div as follows:

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

JavaScript Fix:

Here is the working code snippet:

/* Styles for collapsible content button */
.collapsible {
  background-color: transparent;
  color: #444;
  cursor: pointer;
  width: auto;
  border: none;
  text-align: left;
  outline: none;
  font-size: 15px;
}

.collapsible-active, .collapsible:hover {
  text-decoration: underline;
}

/* Styles for collapsible content. Initially hidden */
.collapsible-content {
  max-height: 100%;
  padding: 10px;
  overflow: hidden;
  transition: max-height 0.2s ease-out;
}

.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>

Explanation behind the solution:

The reason why changing the external css file directly does not work is due to how the JavaScript function reads the content.style.maxHeight. When it's null (as in the original case), modifying only the external CSS doesn't affect this value. But by setting the initial inline css to "max-height: 100%", the JavaScript correctly returns the desired value when accessing content.style.maxHeight.

In order to fix this in HTML/CSS, updating the inline css is necessary to override the external css effectively. For JavaScript, utilizing

window.getComputedStyle(content).maxHeight
ensures that the computed style is considered, including both inline and external styles.

Answer №2

Give this a try

<script>

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

        var btnId = this.id;
        var secId = btnId.replace("btn","section");
        var content = document.getElementById(secId);

        var isCustomMode = content.classList.contains('default-visible-collapsible-content');

    if (isCustomMode) {
      content.classList.remove("default-visible-collapsible-content");
      content.style.maxHeight = 0;
    }

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

<button class="collapsible active-collapsible" id="toggle-btn-0" onclick="animateCollapsibleSectionToggle.call(this)"><b>View Details</b> (show/hide)</button>
<div class="collapsible-content default-visible-collapsible-content" id="visible-section-0">

<h2>
Details go here
</h2>


</div>

I have configured it for post-click display.

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Exploring the possibilities of infinite scroll in JavaScript using the Backbone framework

I've been grappling with this problem for three days straight. I've been attempting to incorporate scrolling into my backbone project using the https://github.com/paulirish/infinite-scroll plugin. Despite my best efforts to find a solution throu ...

How to achieve the wrapping functionality in ReactJS that is similar to

Is there a ReactJS equivalent to jQuery's wrap method? I want to wrap menuContents with the following element: <ul className="nav nav-pills nav-stacked"></ul> The contents of menuContents are generated like this: let menuContents = thi ...

Tips for featuring the latest blog post at the top of a NextJS blog

I have a website built on Next JS with a blog page. The setup is correct, where the /blog page displays content based on slugs. Currently, new blog posts are appearing at the bottom of the page, under older ones. I want to reverse this so that when a new p ...

Error encountered while attempting to render a form within a partial in Rails 5: "simple_fields_for" method is not defined for the SimpleForm::FormBuilder instance

This is a continuation from this thread: Passing a form as a local to a ajax rendered partial in Rails 5 I've searched extensively but haven't been able to find a working solution. Relevant Controller (profits_controller.rb): def new_tabs ...

Effortlessly add and manipulate multiple classes in a generic class using querySelectorAll and classList, eliminating the

I'm encountering an issue that requires me to repeatedly utilize querySelectorAll with Element.classList. Each time, I must convert the NodeList obtained from Element.querySelectorAll into an Array. Then, I need to iterate over the Array using a for ...

What is the best way to enable a link upon clicking while simultaneously disabling the others using JavaScript?

When I click on a link, I want to handle just that one element. However, when I click on another link, the active class is not being removed from the previous ones. Can anyone offer assistance with this issue? Here's my code: let parentT = document.qu ...

Creating a mobile-friendly navigation bar with Vuetify for optimal responsiveness

I am attempting to utilize a vuetify tab component as my navigation menu in order to create a responsive navbar using vuetify. The goal is to have a normal navbar that functions like usual, but when viewed on a mobile device, it should hide the menu and di ...

Using jQuery to update the CSS background of a selected element among multiple elements sharing the same class

I am currently developing a basic jQuery script that will enable the background color of the clicked element to change. Below is the code I have so far: <dt> <input id="p_method_banktransfer" value="banktransfer" type="radio" name="payment[metho ...

How can we combine Angular Gradients and CSS Webkit Gradients for a modern design

Can a gradient be created that resembles the color picker style shown here? The outer part showing full saturated, 50% brightness values and transitioning towards the inside to 100% brightness. https://i.sstatic.net/ohuF4.jpg ...

I am having trouble accessing the database. Jacky @ localhost Password: NO

https://i.sstatic.net/7Kvfu.png What is preventing me from accessing the database? Username: jacky @ local host Password: NO ...

File input onChange event not triggering after pressing SPACE or ENTER key

My React component features an img tag that allows users to select an image from their computer to display in it. While this component functions correctly on most browsers, I encountered an issue specifically with Chromium based browsers (tested on Chrome, ...

Using LocalStorage in Greasemonkey

I am currently working on developing a Greasemonkey script, but I am encountering difficulties with implementing local storage within it. The method I found to work with local storage in Greasemonkey involves creating another instance of JavaScript using t ...

When additional lines are drawn elsewhere on the HTML5 Canvas, the diagonal lines will gradually appear thicker and more pronounced

For horizontal and vertical lines, using a translation of 0.5 for odd stroke widths results in crisper and sharper lines. But what about diagonal lines? Link to jsfiddle <!DOCTYPE html> <html lang="en"> <body style="background: black"& ...

I'm currently facing difficulties trying to implement AJAX with JavaScript and PHP as the desired output is not being

My query is quite straightforward - why isn't the code functioning properly? I am attempting to have the text echoed in PHP displayed inside a div with the ID of "show". Interestingly, this works with a txt file but not with PHP or any other type of f ...

Dealing with a passed EJS variable in string form

When working with passed data in ejs, I usually handle it like this and it works perfectly: let parsed_json = JSON.parse('<%-JSON.stringify(passed_data)%>'); However, I encountered a problem when trying to dynamically pass a string variabl ...

Any ideas for handling ProtractorJS timeouts while clicking an element?

The Issue at Hand I am currently facing a challenge with clicking a straightforward 'New Booking' button in my Angular 5 Material 2 Application. The code snippet for the button is as follows: <button _ngcontent-c9="" class="mat-menu-item" ma ...

Tips for adding animation to the div instead of the content

I have implemented a hover animation to animate the div, but unfortunately, when I added the animation to #i :hover {}, it ended up animating the words only. Moreover, the cursor transforms into a pointer solely when hovering over the words instead of the ...

Restricting zooming to only occur within the img element in a UI

Is there a method to enable image zoom inside specific divs without affecting the overall page zoom? At the moment, I have: <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=0, minimum-scale=1.0, maximum-scale ...

What is the best way to insert data from a promise into MongoDB?

While attempting to integrate an array of JSON data from a different server into a MongoDB collection, I encountered the following error message: "Cannot create property '_id' on string". Even though I am passing in an array, it seems to be causi ...

Generate a new item using an existing one

I am seeking to extract the desired output from the provided input: Input Configuration: var inputParams = { 'inputDetails' :[ { 'field' : 'specificationName', 'value' : 'strong'}, { ...