Blog · 13 min read

Accordion Accessibility for Developers: 7 Checks to Build and Test

Developer keyboard-testing a dim accordion page

An accessible accordion needs several things: a semantic control (a native <details>/<summary> or a <button> trigger), programmatic state through aria-expanded, standard keyboard support with Enter, Space, and Tab, and manual screen reader and keyboard testing. Those requirements trace back to WCAG 2.2 SC 4.1.2 (Name, Role, Value), the USWDS accordion guidance, and the W3C WAI-ARIA Authoring Practices.


TL;DR:

  • Use native details and summary elements for simple disclosures; the name attribute supports single open panels where browsers support it, otherwise use a small script.

  • For custom accordions, place each real button inside a heading, sync aria-expanded on every toggle, connect its panel with aria-controls, and use unique IDs.

  • Keep collapsed content out of the tab order and accessibility tree; when closing a panel that holds focus, return focus to its trigger first.

  • Test with keyboard alone and NVDA or VoiceOver, then repeat on the complete page; passing an isolated component check does not establish sitewide compliance.

  • Reserve accordions for optional content, use descriptive labels, and avoid live regions unless content changes dynamically, since panel expansion is already announced through aria-expanded.


AccessWiser
accesswiser.com
Catch Accessibility Issues Beyond Accordions
AccessWiser scans websites against WCAG 2.2 AA criteria, links findings to affected elements, and provides plain-language guidance for fixes in your code.
Explore AccessWiser

Table of Contents

Which markup pattern should your accordion use?

You have two sound routes. Pick the simpler one that still covers your interaction needs.

Native <details> and <summary> is the strongest default for simple disclosures. The browser supplies the expanded and collapsed state and the toggle behavior, so you ship little or no JavaScript. Native elements also carry less risk of accessibility regressions, and the newer name attribute on <details> gives you exclusive-open behavior (opening one closes the others) without scripting, where browsers support it. Where it is not supported, a small script that closes the other panels does the same job.

Native elements stop being enough when you need richer header content, custom animation, or exclusive behavior in browsers that lack the name attribute. That is where the ARIA and button pattern earns its place. The W3C accordion pattern defines it, and it needs these pieces:

  • A real <button> as the trigger, never a div or span

  • aria-expanded="true" or "false" on that button, kept in sync with the panel

  • aria-controls on the button, pointing to the panel’s id

  • A heading element wrapped around the button, with an aria-level or heading rank that fits the page outline

  • An optional role="region" on the panel with aria-labelledby pointing back to the button

Do not reach for tab roles here. An accordion is a stack of collapsible sections, and applying role="tab" or role="tablist" misleads screen reader users about how the widget behaves. If you also build tabbed interfaces, our guide to accessible tabs covers the markup habits that differ.

What does a copy-ready implementation checklist look like?

Work through this list when you build or review an ARIA-based accordion. Each step maps to something a scanner or a screen reader user will notice.

  1. Use a <button> for every trigger so it is natively focusable and responds to Enter and Space without extra code.

  2. Wrap each button in a heading element that matches your document outline.

  3. Set aria-controls on the button to the exact id of its panel.

  4. Update aria-expanded in the same function that opens or closes the panel, so the attribute never goes stale.

  5. Hide collapsed panels with the hidden attribute or display: none through your toggle logic, so their contents leave both the visual layout and the accessibility tree.

  6. Give every button and panel a unique id. USWDS testing criteria explicitly check for unique IDs, buttons as headers, and aria-controls associations.

  7. If you add role="region", give each region an accessible name through aria-labelledby.

Common mistakes include the following. Triggers built from non-focusable elements lock out keyboard users, and WebAIM notes that this usually comes from building accordions from scratch with div or span plus custom scripts. A stale aria-expanded tells a screen reader the wrong thing. Duplicated IDs break the aria-controls link. Positioning content off-screen instead of using hidden or display: none leaves collapsed content reachable by Tab and by screen readers.

Pro Tip: Do not set hidden manually in your markup if your component’s JavaScript toggles panels, since USWDS advises letting the script own that state.

If your trigger cannot be a button for some reason, add explicit Enter and Space listeners and make it focusable. We still recommend the real button every time.

How should keyboard and focus behavior work?

People expect an accordion to behave like any other set of buttons, and your job is to avoid surprises. The behavior to deliver:

  • Enter and Space toggle the focused header. Per the USWDS accessibility tests, activating a collapsed header expands its panel, and the same keys collapse it if your implementation supports that.

  • Tab and Shift+Tab move through the headers and into any focusable content inside an expanded panel, in a logical order. Never rearrange tab order with positive tabindex values.

  • Collapsed panels contribute nothing to the tab sequence. Links and form fields inside a hidden panel must not receive focus.

  • Focus indicators stay visible at all times. WCAG 2.2 SC 2.4.7 (Focus Visible) requires it, and SC 2.4.11 (Focus Not Obscured) means a sticky header or cookie banner cannot cover the focused trigger. The Access Board’s WCAG mapping lists focus order and focus indicators among the objectively testable requirements.

  • Do not move focus on toggle unless you have a reason. If you do send focus into a newly opened panel, document that behavior and test it with a screen reader first, because it can interrupt the announcement of the expanded state.

Arrow-key navigation between headers is optional in the APG pattern, so treat it as an enhancement and never as a replacement for Tab. For a broader walkthrough of finding and fixing these problems, see our keyboard accessibility steps for developers.

What will screen readers announce, and how do you test it?

When aria-expanded is present and updates correctly, a screen reader announces the button’s label followed by its state, “expanded” or “collapsed”. USWDS states that when a user activates the trigger, the screen reader should immediately announce the updated state. If you hear only the label, the state is missing or not changing.

Run this manual checklist before you ship:

  • Navigate by keyboard alone and confirm every trigger receives visible focus.

  • Press Enter, then Space, on each trigger and listen for the new state.

  • Confirm that collapsed panels expose no focusable elements and that their text is not read.

  • Test with NVDA on desktop and VoiceOver on a Mac or iPhone, so you cover at least one desktop and one mobile pairing.

  • Repeat everything after CSS and JavaScript are integrated into the real page.

That last step matters more than it sounds.

Component-level testing does not guarantee full compliance: USWDS recommends testing in the context of the entire site, because an isolated component can pass while the page around it fails.

For step-by-step screen reader runs, we cover the process in our NVDA and Firefox testing guide. The Access Board’s baseline tests also stress that state attributes such as aria-expanded must be correct and updated after user interaction.

When should you use an accordion at all?

Accordions hide content, and every hidden section adds interaction cost. CMS design guidance says designers should weigh alternatives and still test for accessibility. A few rules keep them useful:

  • Use accordions for optional or secondary content, and never hide anything users must read to finish a task.

  • Write descriptive labels. “Shipping and return windows” works, “More” and “Click here” do not.

  • Show a visible snippet when scanning users need a clue about what sits inside.

  • Add role="region" sparingly. Practitioners describe landmark proliferation as a real annoyance, because a landmark on every panel clutters the landmarks list. Reserve regions for substantial panels, and name each one.

If discoverability matters, remember that collapsed content still needs to be findable. Search visibility and accessibility overlap heavily, so check both when you ship an accordion.

How do you manage focus inside an accordion?

Most accordions need no focus management beyond the native behavior of a button. Focus starts on the trigger the user activated, and it should stay there after the toggle. That is the safest default, because the user keeps their place and the screen reader finishes announcing the state change.

Moving focus into a panel after opening is a design choice, not a requirement. If you do it, send focus to the panel container or its first meaningful element, and make sure the container can accept focus programmatically with tabindex="-1". Never leave a positive tabindex behind. Closing should return the user to a predictable spot: the header that controls the panel.

Do not trap focus. An accordion is inline page content, not a dialog, so users must be able to Tab out of an expanded panel into the next header or beyond. A focus trap here would break the logical order that WCAG 2.2 expects. The exception is a modal opened from inside a panel, and that modal follows dialog rules: trap focus while it is open, and return focus to the element that launched it when it closes.

One more case deserves attention. When a panel closes while focus sits on an element inside it, that element disappears from the accessibility tree and focus is lost. Handle this by moving focus back to the panel’s header button before hiding the content. Then check the result with a screen reader, since a silent focus loss is easy to miss visually.

How do you manage focus inside an accordion? — overview diagram

How should you handle nested accordions?

Nesting an accordion inside a panel is possible, but each level multiplies the problems a user has to solve. Keep nesting to a minimum whenever you can, and ask whether a flatter structure or a different pattern serves the content better.

If you do nest, treat every level as its own complete accordion. Each inner trigger still needs to be a button inside a heading, with its own aria-expanded, its own aria-controls, and an ID that is unique across the whole page. Duplicated IDs are a common failure, and nesting makes them easier to create when a template renders the same inner component repeatedly.

Heading levels deserve care. If the outer headers are h3, the inner ones belong at h4, so the document outline reflects the hierarchy and screen reader users can navigate by heading. Skipping levels or using the same level for both confuses that outline.

Keyboard behavior must stay consistent. Tab should walk the outer header, then, once its panel is open, the inner headers in order, then the next outer header. Collapsing an outer panel must remove every inner header and its content from the tab sequence, even if an inner panel was open. Test that case explicitly, because it is where stale focusable elements tend to survive.

Keyboard path through nested accordion controls

Finally, resist the urge to preserve every inner open state silently when an outer panel collapses and reopens. If you restore state, make it predictable, and announce nothing misleading. Simple, repeatable behavior is easier for users to learn.

How do animations and transitions affect accessibility?

A smooth height transition looks polished, but it can cause real trouble for users with vestibular disorders, motion sensitivity, or attention and cognitive differences. Movement on screen competes for attention and can make it harder to follow where content went.

Honor the user’s system setting. The prefers-reduced-motion media query lets you disable or shorten transitions for people who ask their operating system to reduce motion. A common approach is to set transition durations to zero inside that query, so panels open and close instantly.

Keep any animation short and subtle, and avoid anything that bounces, flashes, or shifts surrounding content dramatically. Never make an animation the only signal that something changed. The state must still be exposed through aria-expanded and visible cues such as an icon that changes direction.

There is a technical trap too. If you animate height and only apply hidden or display: none at the end of the transition, the panel’s contents can remain in the accessibility tree for a moment, and focusable items inside it can still receive Tab. Update aria-expanded immediately when the user activates the trigger, and remove the collapsed content from the tab order as early as possible, not after the animation completes.

Finally, test with motion reduced. Turn on the operating system setting, reload the page, and confirm that the accordion works identically, just without the movement.

When do ARIA live regions belong inside an accordion?

Usually, they do not. Opening a panel is already announced through the button’s aria-expanded state, and adding a live region on top often produces double announcements that sound noisy and confusing.

Live regions earn their place when content inside an open panel changes dynamically without the user pressing anything: a status message after a form submit, a loading indicator that resolves into results, or an error that appears after validation. In those cases, role="status" (polite) handles routine updates, and role="alert" (assertive) is for urgent problems. Prefer polite unless the user must act right now.

A few rules keep this reliable. Put the live region in the DOM before you inject its message, because many screen readers only announce changes to a region that already exists. Keep the messages short and meaningful. Do not wrap an entire panel in aria-live, since every text change inside would be read aloud.

Be careful when content loads on expand. If a panel fetches data when opened, tell the user what is happening: update the region with “Loading shipping options” and then with the result. Keep aria-expanded accurate from the instant of activation, not after the data arrives, so the state announcement and the loading message do not contradict each other.

If your panel’s content never changes after it opens, skip live regions entirely. The simplest implementation, a button with a correct state attribute, is the one that fails least.

Our perspective: native defaults and a maintenance mindset

We think teams should prefer native elements for simple disclosure and treat every ARIA-based accordion as an exception that needs a written reason. Custom widgets age badly: designs change, scripts get refactored, and the attributes drift out of sync. Document why a component departs from the native default, then include accordion checks in your regular automated scans and keep dated remediation logs, so the next developer inherits evidence, not guesswork.

— The AccessWiser Team

Find and fix accordion issues with AccessWiser

We scan your pages for accessibility issues. Each finding comes with plain-language code guidance tied to WCAG 2.2 AA and Section 508 mappings, so fixes land in your own markup. Plans start with Starter at $24 per month, or you can review our solutions page.

FAQ

What are the accessibility guidelines for accordions?

Use a real button as the trigger, expose its state with aria-expanded, and connect it to its panel with aria-controls. Support Enter, Space, and Tab, and keep focus visible. WCAG 2.2 SC 4.1.2 and the W3C accordion pattern are the normative references.

What is the difference between an accordion and a dropdown?

An accordion is a vertical stack of sections that expand in place and push content down. A dropdown menu opens a floating list of choices layered over the page. They use different interaction models, so each needs its own roles and keyboard handling.

Can Google crawl accordion content?

Accordion content that is present in the page’s HTML is generally available to search engines even when visually collapsed. Content that loads only after a click is less certain, so render important text in the initial markup where you can.

What are the two types of accordions?

Single-expand accordions keep one panel open at a time, while multi-expand accordions let several stay open together. Native <details> elements can do single-expand with the name attribute, and scripts can handle both.

Sources

Articles on this blog are general information about web accessibility, not legal advice. Laws change and their application depends on your specific situation — for decisions with legal consequences, consult a qualified legal professional.

Articles on this blog are general information about web accessibility, not legal advice. Laws change and their application depends on your specific situation — for decisions with legal consequences, consult a qualified legal professional.