Skip to content

Accordion

Tier B. Follows the anatomy template and the conventions.

Shows a list of sections, each of which opens to reveal its content, so a long page stays short. Each section is a native <details> with a <summary> header, which gives the WAI-ARIA Disclosure pattern with no script: the summary is the button, its expanded state comes from the browser, and the content is found by find-in-page even while closed. Sections that share a name form an exclusive accordion: opening one closes the others, natively.

A stack of raised slabs, one per section, like Cards with a gap between them. Each slab’s header row carries a chevron that turns when the section opens; the open section’s content is on the same slab, under the header.

Part Shape Height at 50% Moves
Section Rounded plate, radius.control, bevel.width band elevation.raised (3) Grows and shrinks with its content
Header The slab’s top row, at least the density’s control height — No
Chevron A 7 px chevron at the header’s end Flat (in the captured content) Turns 180° on open, over motion.fast

The header covers the section’s whole width, and is at least target.min (24) high, so it is the target (WCAG 2.5.8).

Face Colour role Text role Material role
Section slab secondary text control (matte)
Header None (on the slab); a 6% text tint on hover text, strong None
Chevron muted; text on hover — None

data-strata-material on a section or on the accordion overrides the material.

State Relief Objects CSS
Rest, closed Slab at elevation.raised, header only Slab at raised height Relief recipe at raised
Open (open) The same slab, grown to hold its content; the chevron turned Same Same
Hover (header) A 6% tint on the header; the chevron in text Same Same
Focus-visible (header) outline: focus.width solid accent around the header Same Same

The slab does not rise or travel: hover and press belong to the header, which is flat. Disabled, selected, invalid and busy do not apply. Under prefers-reduced-motion the chevron turns at once.

One raised primitive per section: the <details> element, from its border box. The header, chevron and content are captured content on it.

Token Prop
colour.secondary, colour.text, colour.muted —
radius.control — (theme or scope)
elevation.raised, bevel.*, shadow.* —
material.roles.control material
target.min, control.height, control.font, space.*, density size
focus.width, focus.offset, motion.fast, motion.easing.standard —
level level
<div class="ug-accordion">
<details class="ug-accordion__item" data-strata-face="raised" name="faq" open>
<summary class="ug-accordion__header">
<span class="ug-accordion__title">Shipping</span>
<span class="ug-accordion__chevron" aria-hidden="true"></span>
</summary>
<div class="ug-accordion__body">
<p>Orders ship within two days.</p>
</div>
</details>
<details class="ug-accordion__item" data-strata-face="raised" name="faq">
<summary class="ug-accordion__header">
<span class="ug-accordion__title">Returns</span>
<span class="ug-accordion__chevron" aria-hidden="true"></span>
</summary>
<div class="ug-accordion__body">
<p>Return any item within 30 days.</p>
</div>
</details>
</div>
  • The outer <div> is the boundary element of the accordion, and each <details> of its section: refs, class and style reach them.
  • Exclusive: the same name on every section (React and Vue: exclusive, which generates one, or name). Without a name, any number of sections can be open.
  • Open state: the open attribute. React and Vue: defaultOpen, or open with onOpenChange (v-model:open in Vue), from the native toggle event. Astro: open.
  • Plain HTML and Astro need no script: <details> is native.
  • No overlay.
Key Action
Tab, Shift+Tab Move between the headers and the controls in open sections (native order)
Enter, Space Open or close the focused section (native)
  • Each header is a button with an expanded state (<summary>), named by its title. Screen readers say “Shipping, expanded, button”. The section is a group.
  • Closed content is not focusable and not read, but find-in-page opens the section that holds a match.

The raised recipe on each section, with the card’s secondary colour. The header is a full-width row (no marker, list-style: none) with the title and the chevron, drawn by two borders turned 45°. Under forced-colors each section has a CanvasText border and the chevron is ButtonText.

  • Plain DOM: a click on the header opens and closes its section; Enter and Space toggle; in an exclusive accordion opening one section closes the open one; without a name, sections open independently; roles and expanded state; axe in light and dark.
  • Bindings: React, Vue and Astro render exactly the markup above; React and Vue report onOpenChange (v-model:open) and follow open.
  • GPU: at Relief and Objects each section is a raised slab (an object slab at Objects); a real click on a header through the GPU opens it, with GPU on, and the slab grows to hold the content.