Accordion and disclosure
Usage
Use an accordion to let people scan section titles of a long checklist or form summary and open only what they need (inspection sections, work-order details on tablet). Use a disclosure for one piece of optional detail ("Show service history"). Don't hide information everyone needs — required fields, errors and the next step stay visible. For switching views of the same object use tabs.
- Single (exclusive, shared
name) — when sections are steps or alternatives; keeps the page short on tablet. - Multiple — when people compare sections; default.
Content: summary text is a noun phrase in sentence case ("Brakes", "Parts used"), with an optional count in the meta slot ("2 checks"). A disclosure's summary says what opens: "Show service history (12 entries)".
Anatomy
- Group (accordion) —
.accordion, bordered container - Item —
<details class="accordion__item" name="…"> - Summary —
<summary class="accordion__summary">: title, meta, chevron - Chevron —
svg.accordion__icon, rotates 180° when open - Panel —
.accordion__panel - Disclosure —
<details class="disclosure">with.disclosure__summaryand.disclosure__panel
Examples
States marked hover and focus-visible are frozen with .is-hover and .is-focus-visible. Those classes share their rule with the real pseudo-class; never use them in product code.
Accordion
Grouped inspection checklist. Items sharing a name close each other (single); without it several stay open (multiple).
Engine and drivetrain
Oil level, coolant, drive belt tension.
Brakes
Front pads 3 mm — replace before 86,000 km. Rear pads 7 mm.
Tyres
Tread depth above 4 mm on all wheels.
Engine and drivetrain
Oil level, coolant, drive belt tension.
Brakes
Front pads 3 mm — replace before 86,000 km.
Lights and electrics
Left brake light replaced on 2 Oct.
Parts used
Brake pads (front), wear sensor, brake cleaner, cable ties.
Labour
Marta Quintero, 08:10–11:40.
Notes for the driver
Bedding-in: avoid hard braking for the first 200 km.
<div class="accordion">
<details class="accordion__item" name="insp-kx219" open>
<summary class="accordion__summary"><span class="accordion__title">Engine and drivetrain</span><span class="accordion__meta">3 checks</span><svg class="accordion__icon" aria-hidden="true" focusable="false"><use href="#icon-chevron-down"></use></svg></summary>
<div class="accordion__panel"><p>Oil level, coolant, drive belt tension.</p></div>
</details>
<details class="accordion__item" name="insp-kx219">
<summary class="accordion__summary"><span class="accordion__title">Brakes</span><span class="accordion__meta">2 checks</span><svg class="accordion__icon" aria-hidden="true" focusable="false"><use href="#icon-chevron-down"></use></svg></summary>
<div class="accordion__panel"><p>Front pads 3 mm — replace before 86,000 km.</p></div>
</details>
<details class="accordion__item" name="insp-kx219">
<summary class="accordion__summary"><span class="accordion__title">Lights and electrics</span><span class="accordion__meta">5 checks</span><svg class="accordion__icon" aria-hidden="true" focusable="false"><use href="#icon-chevron-down"></use></svg></summary>
<div class="accordion__panel"><p>Left brake light replaced on 2 Oct.</p></div>
</details>
</div>
Disclosure
One show/hide for secondary detail next to the content it belongs to.
Show service history (12 entries)
Last three: oil change 14 Mar, tyre rotation 2 Jun, brake inspection 2 Oct.
<details class="disclosure">
<summary class="disclosure__summary"><svg class="disclosure__icon" aria-hidden="true" focusable="false"><use href="#icon-chevron-right"></use></svg>Show service history (12 entries)</summary>
<div class="disclosure__panel">
<p>Last three: oil change 14 Mar, tyre rotation 2 Jun, brake inspection 2 Oct.</p>
</div>
</details>
API
| Hook | Values | Purpose |
|---|---|---|
.accordion | block class | Group container with dividers |
.accordion__item | part class on <details> | One section |
name="group-id" | attribute | Same value on all items = only one open at a time (native exclusive accordion) |
open | attribute | Expanded state (set initially for sections that start open) |
.accordion__summary | __title | __meta | __icon | __panel | part classes | Header row and content |
.disclosure, .disclosure__summary | __icon | __panel | block + parts | Single show/hide |
.is-hover | .is-focus-visible | docs-only class | Freeze summary states |
Do and don't
Summary: "Brakes · 2 checks"
Summary: "Click here to see more information about brakes"
<details><summary>
<summary><h3>…</h3></summary>
Accessibility
| Key | Behavior |
|---|---|
| Tab | Moves between summaries (and into open panels' content) |
| Enter / Space | Opens or closes the focused section |
- Role:
<summary>is exposed as a button with expanded/collapsed state; nothing to add. - Exclusive groups use the native
nameattribute; opening one closes the others and the browser updates every state. - Find-in-page and fragment links open closed sections automatically (content stays in the DOM).
- Chevron is decorative (
aria-hidden); the open state is announced, not drawn only. The disclosure chevron mirrors in RTL. - Motion: height animates with
::details-contentwhere supported, instantly elsewhere and under reduced motion. - Target: accordion summaries are at least 44px high (
--size-touch-target).
Tokens
| Custom property | Purpose |
|---|---|
--size-touch-target | Minimum summary height |
--color-border-default | Group border and dividers |
--color-action-ghost-bg-hover | Summary hover fill |
--color-text-link | Disclosure trigger text |
--color-text-muted | Meta text |
--icon-size-md | -sm, --icon-stroke | Chevrons |
--motion-duration-base, --motion-easing-standard | Chevron rotation and height animation |
--focus-ring-* | Inset focus ring on summaries |