Accessible accordion
Updated October 14, 2026 · 5 min read
Accordions keep long pages manageable: FAQ, delivery and returns, product details, filter groups. The APG defines one as "a vertically stacked set of interactive headings that each contain a title, content snippet, or thumbnail representing a section of content" — the headings show or hide their panels. This page shows the correct markup. It is part of the accessible UI patterns series.
When to use an accordion
- Several independent sections where users want only one or two: FAQ, size and care, shipping and returns.
- Mobile layouts where tabs do not fit.
- Filter groups in a category sidebar.
Do not hide essential information in a closed panel when most users need it — price, availability and main product data belong in the open page.
Relevant WCAG criteria
- 4.1.2 Name, Role, Value (A): each header is a button with an expanded or collapsed state.
- 1.3.1 Info and Relationships (A): section titles are real headings.
- 2.4.6 Headings and Labels (AA): headings describe their section.
- 2.1.1 Keyboard (A) and 2.4.7 Focus Visible (AA).
- 1.4.11 Non-text Contrast (AA): the plus or chevron icon that shows the state needs 3:1.
- 2.5.8 Target Size (Minimum) (AA): the whole header row is the target, not only the icon.
Code example
<!-- APG accordion: heading > button, panel controlled by the button -->
<h3>
<button type="button" id="acc-shipping" aria-expanded="true" aria-controls="panel-shipping">
Shipping and delivery
</button>
</h3>
<div id="panel-shipping">
<p>Orders placed before 2 pm are shipped the same working day.</p>
</div>
<h3>
<button type="button" id="acc-returns" aria-expanded="false" aria-controls="panel-returns">
Returns
</button>
</h3>
<div id="panel-returns" hidden>
<p>You can return items within 30 days.</p>
</div>
<!-- Native alternative for independent sections -->
<details>
<summary>Care instructions</summary>
<p>Machine wash at 30 °C.</p>
</details>
Notes from the APG accordion pattern:
- The title of each header is in an element with role
button, which is wrapped in a heading with an appropriate level, and the button "is the only element inside the heading". aria-expandedistruewhen the panel is visible,falsewhen it is hidden;aria-controlsreferences the panel.- If a panel is open and the accordion does not allow it to be collapsed, its button has
aria-disabled="true". - Each panel may have
role="region"witharia-labelledbypointing to its button. This is optional, and the APG advises against it when many panels can be expanded at once (about six or more), because it creates too many landmarks. - The script toggles
aria-expandedand thehiddenattribute. Rotate the chevron with CSS based on[aria-expanded="true"]so the visual state cannot get out of sync.
details and summary give you the button, the state and the keyboard behaviour without any script. They are a good fit for FAQ and care instructions; use the ARIA version when the section titles must also be headings in the page structure.
Keyboard interaction
From the APG accordion pattern:
| Key | Function |
|---|---|
| Enter or Space | On a collapsed header: expands its panel (and, if only one may be open, collapses the other). On an expanded header: collapses it, if the accordion allows that |
| Tab | Next focusable element; all headers and focusable content in open panels are in the tab sequence |
| Shift + Tab | Previous focusable element |
Common mistakes on online shops
- Clickable
divheaders with a chevron icon — no button, no state, no keyboard. - The heading inside the button or the button wrapping the whole panel, which breaks the heading structure.
aria-expandedset once and never updated.- Closed panels hidden with
max-height: 0but their links still receive focus. - FAQ questions styled as headings but marked up as
porspan, or headings that skip levels. - Only the small "+" icon is clickable, not the title.
- Filter accordions that reload the page when opened, losing focus.
What automated checks catch vs manual testing
| Automated (axe-core rule) | What it finds |
|---|---|
button-name |
Header buttons without a name |
summary-name |
summary elements without a name |
aria-valid-attr-value |
Invalid aria-expanded values, aria-controls pointing to missing IDs |
empty-heading, heading-order |
Empty headings, skipped heading levels (advice) |
nested-interactive |
Links or buttons inside the header button |
aria-hidden-focus |
Focusable links inside a panel hidden with aria-hidden |
landmark-unique |
Many region panels with the same name (advice) |
All are cards in our rule library. Manual testing: open and close every section with Enter and Space, check that a screen reader announces "collapsed" and "expanded", that closed panels cannot receive focus and that the state icon is visible in both themes and at 200% zoom.
Run the free one-page check. It is an automated check, not a full audit.
Frequently asked questions
How do I build an accessible accordion?
Put each section title in a heading, and inside the heading a button with aria-expanded and aria-controls that shows or hides the panel. That is the APG accordion pattern. Native details and summary elements are a simpler alternative for independent sections.
Which keys does an accordion need?
Enter or Space on a header button opens or closes its panel, and Tab and Shift + Tab move through the headers and any links in open panels. No arrow keys are required.
Should each accordion panel have role="region"?
It is optional. The APG says to avoid it when many panels can be open at the same time, around six or more, because it creates too many landmarks.
Is content in a closed panel a problem for accessibility?
No, content in a closed panel is fine as long as the button is reachable and announces its state. The content must be hidden properly, for example with the hidden attribute, so that it cannot receive focus while closed.
Can an automated check test an accordion?
It finds header buttons or summary elements without a name, empty headings, invalid aria-expanded values and aria-controls pointing to missing IDs. Whether the state changes and the panel opens with the keyboard needs a manual test.
Sources
- W3C WAI, APG Accordion pattern: https://www.w3.org/WAI/ARIA/apg/patterns/accordion/
- W3C WAI, APG Disclosure pattern: https://www.w3.org/WAI/ARIA/apg/patterns/disclosure/
- WHATWG, HTML Living Standard, interactive elements (details and summary): https://html.spec.whatwg.org/multipage/interactive-elements.html