// pattern
Accessible Accordion Pattern
Expandable content sections built on native HTML <details> and <summary> elements. Full keyboard and screen reader support with zero JavaScript.
// 01 · live demo
Live Demo
Click any section heading or press Enter/Space when focused to expand or collapse it.
What is web accessibility?
Web accessibility means designing and developing websites so that people with disabilities can perceive, understand, navigate, and interact with them. This includes people with visual, auditory, motor, and cognitive disabilities.
What is WCAG 2.2?
WCAG 2.2 (Web Content Accessibility Guidelines) is the latest version of the international standard for web accessibility. It defines success criteria organized under four principles: Perceivable, Operable, Understandable, and Robust. It adds 9 new criteria to WCAG 2.1, including focus appearance, dragging movements, and target size requirements.
Do I need JavaScript for accessible accordions?
No. The native HTML <details> and <summary> elements provide expand/collapse behavior, keyboard interaction, and screen reader semantics with zero JavaScript. You only need JS if you want "exclusive" accordion behavior where opening one section closes the others.
Can multiple sections be open at once?
Yes, and that's the default behavior with <details>. Each section operates independently — users can open as many sections as they want. This is generally better for usability than "exclusive" accordions that close other sections automatically, since users may want to compare content across sections.
Inaccessible version (div-based):
This section can't be toggled with keyboard. The "+" offers no semantic meaning. Screen readers don't know this is expandable.
No keyboard support, no screen reader announcements, no expand/collapse state conveyed.
// 02 · the code
The Code
<!-- Each section is an independent details element -->
<div class="accordion">
<details open>
<summary>
<h3>Section Title</h3>
<svg class="accordion-icon" aria-hidden="true">
<!-- Chevron icon rotates when open -->
</svg>
</summary>
<div class="accordion-content">
<p>Section content goes here.</p>
</div>
</details>
<details>
<summary>
<h3>Another Section</h3>
<svg class="accordion-icon" aria-hidden="true">
<!-- Chevron icon -->
</svg>
</summary>
<div class="accordion-content">
<p>More content here.</p>
</div>
</details>
</div>
<!-- Use the "open" attribute to expand
a section by default -->
.accordion {
border: 1px solid #d1d5db;
border-radius: 0.75rem;
overflow: hidden;
}
.accordion details {
border-bottom: 1px solid #d1d5db;
}
.accordion details:last-child {
border-bottom: none;
}
/* Remove the default disclosure triangle */
.accordion summary {
display: flex;
align-items: center;
justify-content: space-between;
padding: 1rem 1.5rem;
cursor: pointer;
font-weight: 600;
list-style: none;
/* SC 2.5.8: minimum 24x24 target */
min-height: 2.75rem;
}
.accordion summary::-webkit-details-marker {
display: none;
}
.accordion summary::marker {
content: "";
}
.accordion summary:hover {
background: #f8f9fa;
}
/* Chevron icon rotates when section is open */
.accordion-icon {
width: 1.25rem;
height: 1.25rem;
flex-shrink: 0;
transition: transform 200ms ease;
}
details[open] .accordion-icon {
transform: rotate(180deg);
}
/* Focus styles: SC 2.4.13 compliant */
.accordion summary:focus-visible {
outline: 2px solid #5b2a86;
outline-offset: 2px;
border-radius: 0.25rem;
}
.accordion-content {
padding: 0 1.5rem 1.5rem;
}
/* Respect reduced motion */
@media (prefers-reduced-motion: reduce) {
.accordion-icon {
transition: none;
}
}
<details> element handles expand/collapse, keyboard activation, and screen reader state announcements natively. The only CSS interaction is rotating the chevron icon when the open attribute is present.
// 03 · why these decisions
Why These Decisions
Why <details>/<summary> instead of buttons and divs?
The native <details> element gives you critical accordion behavior for free:
- Expand/collapse — toggling content visibility without any JavaScript
- Keyboard support — Enter and Space toggle the section
- Screen reader state — announces "collapsed" or "expanded" automatically
- Focus management — the
<summary>is natively focusable - Semantic meaning — assistive technology understands this is a disclosure widget
Building this from scratch with <div> elements requires JavaScript for toggling, ARIA attributes for state, tabindex for focusability, and keyboard event listeners — all of which the native elements handle automatically.
Why allow multiple sections open simultaneously?
With native <details>, each section operates independently. This is better for usability because users can compare content across sections, open exactly the sections they need, and there is no unexpected content disappearing when they open a new section. "Exclusive" accordions (where opening one closes the others) require JavaScript and can frustrate users who want to reference multiple sections.
Why put headings inside <summary>?
Headings inside <summary> elements create entries in the document outline. Screen reader users who navigate by heading can jump directly to any accordion section without tabbing through all the content. Without headings, accordion sections are invisible to heading-level navigation — one of the most common ways screen reader users scan a page.
Why replace the default disclosure triangle?
The browser's default triangle is small and inconsistently styled across browsers. A custom chevron icon provides a clearer visual affordance, meets minimum target size requirements, and can be animated to communicate state changes. The rotation from "pointing down" (closed) to "pointing up" (open) is a widely understood convention.
Why use the open attribute for default-expanded sections?
The open attribute on <details> is the native way to pre-expand a section. It works without JavaScript and is reflected in the accessibility tree. Use it for the most important section or the one users are most likely to need first.
// 04 · keyboard interaction
Keyboard Interaction
| Key | Action |
|---|---|
| Tab | Moves focus to the next <summary> element (or other focusable element on the page) |
| Shift + Tab | Moves focus to the previous <summary> element |
| Enter | Toggles the focused <details> section open or closed |
| Space | Toggles the focused <details> section open or closed |
<summary> is a separate focusable element in the tab order, which matches how native <details>/<summary> elements work. The WAI-ARIA Accordion Pattern suggests arrow keys for ARIA-based accordions, but native elements follow native behavior.
// 05 · wcag 2.2 success criteria
WCAG 2.2 Success Criteria
This pattern satisfies the following WCAG 2.2 success criteria:
- 2.1.1 Keyboard Level A — All accordion functionality is operable via keyboard. Enter and Space toggle sections; Tab navigates between them.
-
1.3.1 Info and Relationships
Level A
— The
<details>/<summary>structure conveys the relationship between section headers and their content programmatically. Headings inside<summary>provide document structure. -
2.4.3 Focus Order
Level A
— Focus moves through
<summary>elements in logical document order via Tab. - 2.4.6 Headings and Labels Level AA — Each accordion section has a descriptive heading that clearly identifies its content.
-
2.4.11 Focus Not Obscured (Minimum)
Level AA
— Focused
<summary>elements are fully visible, not hidden behind other content. - 2.4.13 Focus Appearance Level AAA — Focus indicators use a 2px solid outline with 3:1 contrast ratio.
-
2.5.8 Target Size (Minimum)
Level AA
— Each
<summary>element spans the full width and meets the 24x24px minimum target size. -
4.1.2 Name, Role, Value
Level A
— The
<details>element exposes its expanded/collapsed state to the accessibility tree automatically. No manual ARIA state management required.
// 06 · screen reader behavior
Screen Reader Behavior
When navigating to a collapsed section
- NVDA: "What is WCAG 2.2? heading level 3, collapsed, summary" — announces the heading, the collapsed state, and the element role
- JAWS: "What is WCAG 2.2? collapsed" — announces heading text and state
- VoiceOver: "What is WCAG 2.2? heading level 3, summary, collapsed, group" — announces heading, role, state, and the group context
When expanding a section
- NVDA: "expanded" — announces the new state after pressing Enter or Space
- JAWS: "expanded" — same state announcement
- VoiceOver: "expanded" — confirms the state change
After expansion, the content below the <summary> becomes visible and navigable. Screen reader users can continue reading with arrow keys or use Tab to reach focusable elements within the expanded content.
Navigating by heading
Because each <summary> contains a heading element, screen reader users can use heading navigation (H key in NVDA/JAWS, rotor in VoiceOver) to jump between accordion sections. This makes it fast to scan the available sections without tabbing through each one sequentially.
// 07 · common mistakes
Common Mistakes
<div> with click handlers instead of <details>/<summary>
Building accordions from <div> elements requires manually adding role="button", tabindex="0", aria-expanded, aria-controls, keyboard event listeners, and JavaScript toggle logic. The native elements provide all of this for free. The only reason to use ARIA-based accordions is if you need "exclusive" behavior (opening one closes others) — and even then, consider whether that's truly necessary.
<summary>, screen reader users who navigate by headings can't find or jump to accordion sections. They'd have to tab through every focusable element on the page. Always include a heading (typically <h3> or the appropriate level for your document outline) inside each <summary>.
<h2>, the accordion headings should be <h3> — not <h2> or <h4>. Broken heading hierarchy confuses screen reader users and reduces the usefulness of heading navigation.
<details> elements is still in the DOM and indexable by search engines. This is a feature, not a bug. Don't use accordions to hide content you want indexed — the content is always there. But also don't worry that collapsed content won't be found by search engines — it will be.
display: none toggling
Some JavaScript-based accordions use display: none to hide content and toggle it on click. This breaks the flow for screen readers and prevents the smooth expand/collapse experience that native <details> provides. If you must animate the expansion, use height transitions or the @starting-style at-rule instead of display toggling.
// 08 · native html vs. aria
Native HTML vs. ARIA
This comparison shows what <details>/<summary> gives you for free versus building an accordion manually with ARIA.
| Feature | <details>/<summary> (native) |
ARIA accordion (<div> + ARIA) |
|---|---|---|
| Expand/collapse behavior | Automatic — built into the element | Manual — JavaScript toggle logic |
| Keyboard activation | Automatic — Enter/Space | Manual — keydown event listeners |
| Focusable trigger | Automatic — <summary> is focusable |
Manual — tabindex="0" |
| Expanded/collapsed state | Automatic — open attribute |
Manual — aria-expanded="true/false" |
| Screen reader role | Automatic — disclosure widget | Manual — role="button" on trigger |
| Content association | Automatic — content is inside <details> |
Manual — aria-controls pointing to content ID |
| Multiple open sections | Automatic — default behavior | Manual — toggle logic per section |
| Default expanded | <details open> |
Manual — set initial aria-expanded and show content |
| JavaScript required | None | Yes — significant amount |
| Browser support | All modern browsers (97%+) | Depends on ARIA support |
<details>/<summary> eliminates all JavaScript and all ARIA attributes needed for an accordion. The only things you add are CSS for styling and headings inside <summary> for document structure. This is as close to "zero effort accessibility" as it gets.