A11y Patterns
All patterns
Pattern

Accordion

A component for collapsing and expanding content by section

Related WCAG criteria — click to view details

01 — Code

Code example

Baseline (React)tsx
Loading...
02 — Rules

Common baseline

Applies to all design systems
Must4
  • Button role on headers

    Each section heading must use role="button" or a <button> element.

  • aria-expanded on each header button

    aria-expanded="true" when the panel is open, aria-expanded="false" when closed.

  • Header button references its panel

    Each header button must reference its panel id via aria-controls.

  • Toggle panel with Enter/Space

    Panels must be toggled open and closed with Enter or Space.

Should3
  • Wrap button in a heading element

    Place buttons inside an appropriate h2–h6 heading to maintain document structure.

  • Arrow key navigation between headers

    Down arrow moves to the next header, up arrow moves to the previous header.

  • Home/End to first/last header

    Home navigates to the first header, End navigates to the last header.

Avoid2
  • Do not use button without a heading

    Using a button without a heading wrapper prevents screen readers from navigating the document structure.

  • Do not force single-expand without notice

    If auto-closing other panels, clearly communicate this behavior to users.

03 — Implementations

Design system implementations

Additional checks

  • Set id and aria-controls on AccordionSummary

    Per WAI-ARIA guidelines, set id on AccordionSummary and aria-controls pointing to the panel id. MUI derives aria-labelledby automatically from these.

  • Adjust heading level with slotProps.heading

    MUI Accordion defaults to h3. Change the heading level using slotProps={{ heading: { component: "h2" } }} to match your page hierarchy.

Code sample

MUI Accordiontsx
Loading...

Implementation notes

  • aria-expanded is managed automatically based on the expanded prop state.
  • Set id and aria-controls on AccordionSummary; MUI derives aria-labelledby for the panel automatically.
  • Use slotProps={{ heading: { component: "h3" } }} to adjust heading level to match page structure.
  • Use slotProps={{ transition: { unmountOnExit: true } }} to remove inactive panels from the DOM for better performance.
04 — References

References