Collapse: Toggling Content

Intermediate
10 min

Collapse: Toggling Content

Collapse is the plugin behind accordions, the navbar hamburger menu, and any "show more" section. It animates an element's height between zero and its natural size, updates ARIA attributes, and can be driven by data attributes or JavaScript. Understanding it on its own makes the components built on top of it much easier to debug. This lesson covers single and multiple targets, horizontal collapse, the JavaScript API and events.

Basic Usage

A trigger with data-bs-toggle="collapse" and a target element with the .collapse class:

html
<p> <a class="btn btn-primary" data-bs-toggle="collapse" href="#details" role="button" aria-expanded="false" aria-controls="details">Link trigger</a> <button class="btn btn-primary" type="button" data-bs-toggle="collapse" data-bs-target="#details" aria-expanded="false" aria-controls="details">Button trigger</button> </p> <div class="collapse" id="details"> <div class="card card-body">Hidden by default, revealed with a height animation.</div> </div>
  • Links use href="#id"; buttons use data-bs-target="#id".
  • aria-expanded is kept in sync by the plugin; aria-controls links the trigger to the target for assistive technology.
  • Add .show to the target to start expanded.

During the animation the element has the .collapsing class; when open it has .collapse.show. Because the animation is based on height, put padding on an inner element (the .card-body above), not on the .collapse element itself, or the transition will jump.

Horizontal Collapse

Add .collapse-horizontal to animate width instead of height. The inner element needs an explicit width:

html
<button class="btn btn-secondary" data-bs-toggle="collapse" data-bs-target="#sidebar">Toggle sidebar</button> <div class="collapse collapse-horizontal" id="sidebar"> <div class="card card-body" style="width: 280px">Slides in from the left.</div> </div>

Multiple Targets

One trigger can toggle several elements by using a class selector, and several triggers can toggle the same element:

html
<button class="btn btn-primary" data-bs-toggle="collapse" data-bs-target=".multi">Toggle both</button> <button class="btn btn-secondary" data-bs-toggle="collapse" data-bs-target="#first">Only first</button> <div class="row mt-3"> <div class="col"> <div class="collapse multi" id="first"><div class="card card-body">First</div></div> </div> <div class="col"> <div class="collapse multi" id="second"><div class="card card-body">Second</div></div> </div> </div>

When a trigger controls multiple targets, aria-controls should list every ID separated by spaces.

Accordion Behavior with data-bs-parent

Setting data-bs-parent="#groupId" on each collapsible closes the others in that group when one opens. This is exactly what the accordion component does under the hood; you can use it on your own markup, for example a FAQ built from cards:

html
<div id="faq"> <div class="card mb-2"> <button class="btn w-100 text-start" data-bs-toggle="collapse" data-bs-target="#q1">Is there a free tier?</button> <div class="collapse show" id="q1" data-bs-parent="#faq"><div class="card-body">Yes, up to 3 projects.</div></div> </div> <div class="card mb-2"> <button class="btn w-100 text-start" data-bs-toggle="collapse" data-bs-target="#q2">Can I cancel anytime?</button> <div class="collapse" id="q2" data-bs-parent="#faq"><div class="card-body">Yes, from the billing page.</div></div> </div> </div>

JavaScript API

javascript
import { Collapse } from "bootstrap"; // Create without opening (data attributes open immediately by default) const filters = new Collapse("#filters", { toggle: false }); filters.show(); filters.hide(); filters.toggle(); filters.dispose(); // Reuse an existing instance Collapse.getOrCreateInstance(document.getElementById("filters")).toggle();

Options: toggle (default true, toggles on initialization) and parent (selector for accordion behavior).

Events fire on the collapsible element:

| Event | When | |---|---| | show.bs.collapse | show called, before the animation | | shown.bs.collapse | Animation complete, element visible | | hide.bs.collapse | hide called | | hidden.bs.collapse | Fully hidden |

Calling event.preventDefault() in show.bs.collapse or hide.bs.collapse cancels the action, useful for a confirmation step.

A practical pattern is updating the trigger's label:

javascript
const target = document.getElementById("details"); const trigger = document.querySelector('[data-bs-target="#details"]'); target.addEventListener("shown.bs.collapse", () => (trigger.textContent = "Hide details")); target.addEventListener("hidden.bs.collapse", () => (trigger.textContent = "Show details"));

Common Mistakes

  • Padding or margin on the .collapse element. The height animation measures the element; outer spacing causes a visible jump. Put spacing on the inner wrapper.
  • new Collapse(el) on an element that should stay closed. Pass { toggle: false }, otherwise it opens immediately.
  • Trigger and target with the same ID prefix but a typo. Nothing happens and no error is thrown; check the selector.
  • Using display: none on .collapse in custom CSS. The plugin manages display; overriding it breaks the animation.
Quick Quiz
Question 1 of 3

What class does the target element have while the animation is running?

Key Takeaways

  • A data-bs-toggle="collapse" trigger targets a .collapse element by href or data-bs-target; .show starts it open.
  • The plugin animates height (.collapse-horizontal animates width) and moves through .collapsing during transitions.
  • Class selectors toggle multiple targets; data-bs-parent gives accordion behavior on any markup.
  • Collapse.getOrCreateInstance(el, { toggle: false }) plus show(), hide() and toggle() control it from JavaScript.
  • show/shown/hide/hidden.bs.collapse events are cancelable and fire on the collapsible element.

Next lesson: Toasts, Spinners and Placeholders - notifications, loading indicators and skeleton screens.

Collapse: Toggling Content - Bootstrap | CodeYourCraft | CodeYourCraft