Collapsible Content

js/collapsible.js

v.1.0 Stable | Download file_download

The collapsible component provides a clean solution for managing large, secondary content or detailed information that might otherwise clutter the interface. When implemented correctly, it allows users to progressively discover content based on their interest level, maintaining a clean, focused interface by default.

This pattern is particularly useful for:

  • FAQ sections
  • Detailed specifications
  • Supplementary information
  • Long descriptions that would disrupt the main content flow

Native HTML Solution

Basic HTML5 provides built-in <details> and <summary> elements for collapsible content that require no JavaScript and work across all modern browsers:

Native HTML Example

HTML5 provides built-in elements for collapsible content that require no JavaScript and work across all modern browsers:

<details>
  <summary>Click to expand</summary>
  <p>This content is hidden by default and appears when the user clicks the summary.</p>
</details>

Using pure HTML elements offer several advantages:

  • Zero JavaScript dependency
  • Built-in accessibility features
  • Native browser support
  • Consistent behavior across platforms

JavaScript

For cases requiring more complex behavior or specific design patterns that go beyond what native HTML elements provide, a custom JavaScript implementation is available:

code Implementation Examplekeyboard_arrow_down

The script handles two common HTML structures:

  • Structure 1: Trigger and content are siblings
  • Structure 2: Trigger inside parent element (like <p>) followed by content

Below is a practical implementation example showing how the collapsible component works.

// Structure 1 (siblings under same parent):
<div class="container">
    <div class="collapsible-trigger">Trigger<span> class="collapsible-icon material-icons-outlined">keyboard_arrow_down</span></div>
    <div class="collapsible-content">Content goes here</div>
</div>
// Structure 2 (content after trigger's parent): <div class="container"> <p> <span class="collapsible-trigger">Trigger<span class="collapsible-icon">...>/span></span> </p> <div class="collapsible-content">Content</div> </div>

Note: The .collapsible-icon element is optional. If it's not present, the script will still toggle the visibility of the content, but there won't be any icon changes.

Technical Requirements

Pay attention for several points:

  1. The clickable element must have class .collapsible-trigger
  2. The hidden content must have class .collapsible-content
  3. Optional: Icon element with class .collapsible-icon
  4. The default state of .collapsible-content should be set as display: none; or max-height: 0; to ensure content is hidden before JavaScript runs
Raw code
document.addEventListener('DOMContentLoaded', function() {
    // Find all trigger elements
    const triggers = document.querySelectorAll('.collapsible-trigger');

    // Add click handler to each trigger
    triggers.forEach(trigger => {
        trigger.addEventListener('click', function() {
            // Try to find related content element
            let content;

            // Check if trigger and content are siblings
            if (this.nextElementSibling && this.nextElementSibling.classList.contains('collapsible-content')) {
                content = this.nextElementSibling;
            }
            // Check if content is the next sibling of trigger's parent
            else if (this.parentElement &&
                        this.parentElement.nextElementSibling &&
                        this.parentElement.nextElementSibling.classList.contains('collapsible-content')) {
                content = this.parentElement.nextElementSibling;
            }

            // Exit if no content found
            if (!content) return;

            // Find the icon (if it exists)
            const icon = this.querySelector('.collapsible-icon');

            // Check if content is currently visible
            const isVisible = window.getComputedStyle(content).display !== 'none';

            // Toggle visibility
            if (isVisible) {
                content.style.display = 'none';
                if (icon) icon.textContent = 'keyboard_arrow_down';
            } else {
                content.style.display = 'block';
                if (icon) icon.textContent = 'keyboard_arrow_up';
            }
        });
    });
});

Pseudo-Link Styling Cheat Sheet

Create a special style for pseudo-links.

Following best practices, .collapsible-trigger elements should be visually distinguished to indicate their interactive nature.

When designing the visual treatment for collapsible triggers, aim for a balance between subtlety and clarity. Users should recognize them as interactive elements without disrupting the flow of content.

Bonus: If it’s part of a bigger text block, avoid display: block — it should feel natural inside the flow.