Create an exclusive accordion with multiple <details>
elements that have the same name
.
The accordion
A common UI pattern on the web is an accordion component. This is a component that consists of several disclosure widgets that individually can be expanded (or collapsed) to reveal (or hide) their content.
To implement this pattern on the web you combine a few <details>
elements and typically group them visually to indicate that they belong together.
The exclusive accordion
Browser Support
A variation of the accordion pattern is the exclusive accordion, in which only one of the disclosure widgets can be opened at the same time.
To create an exclusive accordion on the web you add a name
attribute to the <details>
elements. When this attribute is used, multiple <details>
elements that have the same name
value form a semantic group and they will behave as an exclusive accordion. When you open one of the <details>
elements from the group, the previously opened one will automatically close.
<details name="learn-css">
<summary>Welcome to Learn CSS!</summary>
<p>…</p>
</details>
<details name="learn-css">
<summary>Box Model</summary>
<p>…</p>
</details>
<details name="learn-css">
<summary>Selectors</summary>
<p>…</p>
</details>
A page can have multiple exclusive accordions. Whenever you use a new name
value on a <details>
element, a new logical group is created.
The <details>
elements that are part of an exclusive accordion don't necessarily need to be siblings. They can be scattered across the document. It's the name
attribute that groups them, not their DOM order.
Polyfill the exclusive accordion
With the following JavaScript it's possible to polyfill the behavior of the exclusive accordion. The code relies on the toggle
event of the <details>
element.
When a <details>
element with a name
opens, the code finds the other open <details>
elements with the same value for the name
attribute and closes them.
document.querySelectorAll("details[name]").forEach(($details) => {
$details.addEventListener("toggle", (e) => {
const name = $details.getAttribute("name");
if (e.newState == "open") {
document
.querySelectorAll(`details[name=${name}][open]`)
.forEach(($openDetails) => {
if (!($openDetails === $details)) {
$openDetails.removeAttribute("open");
}
});
}
});
});
Some older versions of browsers don't fire this toggle
event. In those browsers the polyfill code won't do anything. In terms of progressive enhancement, this is acceptable behavior.