Accordion disclosure without JavaScript
Accordions used to need JavaScript to toggle visibility, update aria-expanded, and manage keyboard events. The details and summary elements handle all of that natively.
2<details>
3 <summary>What is CSS?</summary>
4 <p>CSS styles the web.</p>
5</details>
2<button aria-expanded="false" aria-controls="panel">What is CSS?</button>
3<div id="panel" hidden>...</div>
4// JS: toggle hidden + update aria-expanded on click
5btn.addEventListener('click', () => {
6 panel.toggleAttribute('hidden');
7 btn.setAttribute('aria-expanded', !panel.hidden);
8});
Browser Support for Details
This feature is well established and works across many devices and browser versions. It has been available across browsers since 2020.
No JavaScript
Click to expand, click to collapse. Keyboard accessible. The browser manages open state with zero JS.
Accessible by default
The summary element is a button in the accessibility tree. No manual aria-expanded wiring needed.
Styleable with CSS
Target the open attribute to style the expanded state. Use ::details-content for the panel and ::marker or list-style to customize the triangle.
How it works
The <details> element is a disclosure widget. Wrap content in it and add a <summary> as the first child β the summary becomes the visible toggle. Everything else inside details is hidden until the user opens it.
The browser adds the open attribute when expanded. You can hook into it with CSS: details[open] summary { ... }. The disclosure triangle comes from ::marker on the summary β replace it with list-style: none and your own indicator.
For exclusive accordions where only one item is open at a time, give all details elements the same name attribute. The browser enforces mutual exclusivity automatically β no JavaScript needed for that either.