Exclusive Accordion

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.

Demo: Accordion with HTML and CSS.

The exclusive accordion

Browser Support

  • Chrome: 120.
  • Edge: 120.
  • Firefox: 130.
  • Safari: 17.2.

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 achieve this on the web you can now 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>
Demo: Exclusive accordion with HTML and CSS.

A page can have multiple exclusive accordions. Whenever you use a new name value on a <details> element, a new logical group is created.

Demo: Multiple exclusive accordions with HTML and CSS.

Note that 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.