Stop Hand-Rolling an Exclusive Accordion. `<details name>` Does It
You're building an FAQ page. Ten questions, each collapsed by default, and — this part's in every design spec — only one answer open at a time. Click a second question, the first one closes. Standard accordion behavior, the kind you've built before you finish reading the ticket. So you reach for <details> and <summary> , because it's the native disclosure widget and you'd rather not hand-roll…
You are constructing an FAQ page with multiple questions and answers. By default, each question is collapsed and only one answer can be displayed at a time. When you switch to a different question, the previously open answer collapses. This is standard accordion behavior, which you have implemented before. To simplify the process, you opt to use the native `details` element and `summary` tag, as they provide built-in disclosure widget functionality without the need for custom ARIA toggling.
Initially, this approach works well for ten questions. However, when you attempt to open a second question while the first one remains open, both answers remain expanded and occupy the entire viewport. This is because the `details` element does not inherently enforce mutual exclusivity, causing each element to manage its own open state independently.
To resolve this issue, you write a loop that adds an event listener to each question, which closes all other questions when a new one is opened. While this solution works, it introduces additional complexity to the code, requiring a query selector to select all `details` elements with a specific class, attaching an event listener to each, and iterating through each item to close others.
This approach can lead to performance issues, especially if new FAQ blocks are injected into the page after the initial script execution. Furthermore, if the FAQ block is pasted into the content after the page has loaded, the script may not re-initialize, resulting in all panels opening independently without any error message. The spec for the `details` element was updated in late 2023, allowing you to assign a `name` attribute to a group of `details` elements.
When multiple `details` elements share the same `name` value, the browser automatically enforces mutual exclusivity, closing all other members in the same group when one is opened. This behavior works seamlessly across current versions of Chrome, Edge, Firefox, and Safari. The fallback behavior is still functional, maintaining the native disclosure widget state, which is useful for older browsers that do not support the `name` attribute.
Interestingly, you may not have anticipated that the `name` attribute would enable mutual exclusivity regardless of the elements' position in the DOM tree or their container elements. Two `details` elements with the same `name` value, even if they are in different sections of the page, will still behave as a single exclusive group.
The spec recommends grouping related elements together within a parent container for better discoverability, especially for screen reader users. However, it is possible to reuse the `name` attribute accidentally, leading to unexpected behavior where independent accordions may start closing each other's panels without any console warnings.
While the native grouping simplifies the accordion implementation, it does not cover all potential use cases. For instance, if you need to open a panel from an external trigger or if you want to persist the open state across page reloads, you will still need to use JavaScript. Similarly, reacting to which panel was opened (for analytics purposes) or handling anchor links that point to content inside a closed `details` element also requires custom JavaScript.
The mutual-exclusivity feature, which used to be a source of bugs in custom implementations, is now handled automatically by the browser. To demonstrate the difference between the custom JS-loop accordion and the native `name`-grouped accordion, you can interact with an interactive playground that runs directly in your browser. By toggling the `name` value, you can observe how two independent groups start interacting unexpectedly.
This example highlights the advantages of leveraging native HTML elements for building user interface components, as they often come with built-in functionality and fewer maintenance responsibilities.
Written by urgent.news from Dev.to's reporting — not their text. Machine-written — may contain errors; check the original before relying on it.