Accordions consist of a number of content panels, each of which can be expanded or collapsed vertically by the user.
Accordions help to save vertical space and reduce visual noise. Some accordions allow only a single panel to be expanded at a time, others allow multiple.
Before you continue, please read Tablist widgets (or: tab panels, tabs) to understand why accordions simply are extended variants of tablists, providing a slightly different layout and (sometimes) expandability of multiple panels.
Accordions and Tablists share the same underlying logic: a trigger (header/tab) controls the visibility of a content panel. While they are structurally similar, accordions have specific requirements:
Multiple panels can be visible at the same time (optional).
Keyboard support: Users can navigate between accordion headers using Tab and toggle them with Enter or Space. (Optional but recommended: Arrow key navigation).
<p><button>Focusable element before</button></p><sectionclass="accordion-widget accordion"data-adg-accordion="flowers-accordion"><h2>Flowers</h2><divclass="accordion-item"><h3class="accordion-header"><buttonid="accordion_header_rose"class="accordion-trigger"type="button"aria-expanded="true"aria-controls="accordion_panel_rose"><spanclass="indicator indicator-open"aria-hidden="true">-</span><spanclass="indicator indicator-closed"aria-hidden="true">+</span>
Rose
</button></h3><divclass="accordion-panel"id="accordion_panel_rose"role="region"aria-labelledby="accordion_header_rose"><p>A rose is a woody perennial flowering plant of the genus Rosa.</p><p><ahref="https://en.wikipedia.org/wiki/Rose"target="_blank">Learn more about roses</a></p></div></div><divclass="accordion-item"><h3class="accordion-header"><buttonid="accordion_header_tulip"class="accordion-trigger"type="button"aria-expanded="false"aria-controls="accordion_panel_tulip"><spanclass="indicator indicator-open"aria-hidden="true">-</span><spanclass="indicator indicator-closed"aria-hidden="true">+</span>
Tulip
</button></h3><divclass="accordion-panel"id="accordion_panel_tulip"role="region"aria-labelledby="accordion_header_tulip"hidden><p>Tulips are a genus of spring-blooming perennial plants.</p><p><ahref="https://en.wikipedia.org/wiki/Tulip"target="_blank">Learn more about tulips</a></p></div></div><divclass="accordion-item"><h3class="accordion-header"><buttonid="accordion_header_sunflower"class="accordion-trigger"type="button"aria-expanded="false"aria-controls="accordion_panel_sunflower"><spanclass="indicator indicator-open"aria-hidden="true">-</span><spanclass="indicator indicator-closed"aria-hidden="true">+</span>
Sunflower
</button></h3><divclass="accordion-panel"id="accordion_panel_sunflower"role="region"aria-labelledby="accordion_header_sunflower"hidden><p>A sunflower is a large annual plant.</p><p><ahref="https://en.wikipedia.org/wiki/Sunflower"target="_blank">Learn more about sunflowers</a></p></div></div></section><p><button>Focusable element after</button></p>
This implementation follows the current APG approach and uses a real button in each header.
The button toggles aria-expanded (true/false).
The button uses aria-controls to reference the associated panel.
The panel uses role="region" and aria-labelledby to expose a clear relationship back to the controlling header button.
The panel visibility is synchronized with the semantic state using JavaScript.
Native HTML Disclosure Elements
For simple disclosure-like use cases, the native HTML <details> and <summary> elements are a solid, no-JavaScript option. You can find the technical specification and browser behavior in the MDN Web Docs for the Details element.
The summary element works as the interactive header.
The surrounding details element manages the expanded/collapsed state natively.
This removes the need for JavaScript compared to custom ARIA widgets.
<p><button>Focusable element before</button></p><sectionclass="accordion-widget accordion"><h2>Flowers</h2><detailsclass="accordion-item"open><summaryclass="accordion-header accordion-trigger"><spanclass="indicator indicator-open"aria-hidden="true">-</span><spanclass="indicator indicator-closed"aria-hidden="true">+</span>
Rose
</summary><divclass="accordion-panel"><p>A rose is a woody perennial flowering plant of the genus Rosa.</p><p><ahref="https://en.wikipedia.org/wiki/Rose"target="_blank">Learn more about roses</a></p></div></details><detailsclass="accordion-item"><summaryclass="accordion-header accordion-trigger"><spanclass="indicator indicator-open"aria-hidden="true">-</span><spanclass="indicator indicator-closed"aria-hidden="true">+</span>
Tulip
</summary><divclass="accordion-panel"><p>Tulips are a genus of spring-blooming perennial plants.</p><p><ahref="https://en.wikipedia.org/wiki/Tulip"target="_blank">Learn more about tulips</a></p></div></details><detailsclass="accordion-item"><summaryclass="accordion-header accordion-trigger"><spanclass="indicator indicator-open"aria-hidden="true">-</span><spanclass="indicator indicator-closed"aria-hidden="true">+</span>
Sunflower
</summary><divclass="accordion-panel"><p>A sunflower is a large annual plant.</p><p><ahref="https://en.wikipedia.org/wiki/Sunflower"target="_blank">Learn more about sunflowers</a></p></div></details></section><p><button>Focusable element after</button></p>
// Native details/summary behavior requires no JavaScript for basic toggle behavior.
Implementation details
This implementation follows the current APG approach and uses a real button in each header.
The button toggles aria-expanded (true/false).
The button uses aria-controls to reference the associated panel.
The panel uses role="region" and aria-labelledby to expose a clear relationship back to the controlling header button.
Keyboard Navigation: Implementation should ideally support Arrow keys (Up/Down) to move focus between headers, and Home/End to jump to the first/last header.
Comparison: ARIA vs. Native HTML
Comparison of Implementation Methods
Implementation Method
Advantages
Limitations
Custom ARIA Implementation
Full control over keyboard behavior (e.g. arrow keys).
Better for complex layouts/nested widgets.
Exact state control via JS.
Requires JavaScript for state and interaction.
Higher maintenance (must handle all ARIA states manually).
Native Disclosure Elements (<details>)
Works without JavaScript.
Native accessibility "out of the box".
Minimal code footprint.
Limited styling options.
No native support for "only one open" (requires JS).
Default keyboard support is limited to Tab/Space/Enter.
Legacy implementations (Historical)
Note: The following legacy variants are deprecated and provided for historical reference only.
For all new projects, use one of the recommended implementations above (ARIA or native <details>/<summary>, depending on your requirements).