aria-hidden Must Not Contain Focusable Elements: How to Fix It

No Comments
Aria-hidden must not contain focusable elements: how to fix it

TL;DR: An element marked aria-hidden="true" is hidden from screen readers, but if it still contains links, buttons, or inputs, keyboard users can tab right into them. That mismatch (focusable but unannounced) confuses people and fails WCAG 4.1.2. Fix it by removing the focusable controls from the hidden container, taking them out of the tab order with inert or tabindex="-1", or not hiding containers that hold interactive content at all.

What this means

The attribute aria-hidden="true" removes an element and everything inside it from the accessibility tree. Screen readers skip it entirely, as if it were not there. That is useful for decorative icons, duplicate text, or off-screen panels you do not want announced.

The problem starts when a hidden container still holds focusable children: links with an href, buttons, form fields, or anything with a positive tabindex. Hiding from the accessibility tree does not remove an element from the keyboard focus order. So the control is invisible to a screen reader yet still reachable by pressing Tab. The two states disagree.

Why it matters

When a sighted keyboard user or a screen reader user tabs through a page, focus can land on a control that the screen reader announces as nothing, or skips over while the focus ring sits on it. The person hears silence, loses their place, or activates a control they cannot perceive. It is one of the most disorienting accessibility bugs because the page looks fine visually while the experience breaks for the people who rely on focus and announcements lining up.

Deque rates this issue Serious, and it maps to WCAG 2.1 Success Criterion 4.1.2 Name, Role, Value (Level A). It also commonly relates to 1.3.1 Info and Relationships, because the hidden state no longer reflects the real structure exposed to keyboard navigation. The W3C ACT rule "Element with aria-hidden has no content in sequential focus navigation" describes the same requirement.

Why aria-hidden is the wrong tool for hiding controls

The root cause is that different hiding techniques touch different systems. Some remove an element from what a screen reader reads; some remove it from the tab order; the good ones do both at once. This table is the mental model that makes the bug obvious.

TechniqueHidden from screen reader?Removed from tab order?
aria-hidden="true"YesNo — this is the bug
display:noneYesYes
visibility:hiddenYesYes
inert attributeYes (also blocks interaction)Yes
tabindex="-1" (per control)No, on its ownYes, for that control

How to detect it

Automated tools catch this reliably, and one manual pass confirms it fast.

  1. axe DevTools (browser extension). Scan from the axe panel. The rule id is aria-hidden-focus, "ARIA hidden element must not be focusable or contain focusable elements," and it highlights the exact container and its focusable descendants.
  2. Google Lighthouse. Run an Accessibility report in Chrome; the same axe-sourced finding appears in the audit list with the failing nodes, which is handy for a whole-page count.
  3. ARIA DevTools (browser extension), plus a Tab test. Use it to see that the container is absent from the accessibility tree, then press Tab through the page: if the focus ring lands inside a region the screen reader is silent about, you have reproduced the bug by hand.

How to fix it

You have three clean options. Pick based on whether the content should be reachable at all.

1. Take the controls out of the tab order. If a container is genuinely hidden (an off-screen menu, a collapsed panel), make sure nothing inside it can receive focus. The modern way is the inert attribute, which removes a whole subtree from focus and interaction in one step. Use tabindex="-1" per control where you need broader browser support, and add disabled to form fields.

2. Hide it with CSS instead. If the content should be fully gone, use display:none or visibility:hidden. Both remove the element from the accessibility tree and the focus order, so the two stay in sync without needing aria-hidden at all.

3. Do not hide containers that hold live, interactive content. If the buttons and links inside are meant to be used, the container should not be aria-hidden="true" in the first place. Remove the attribute and expose the content properly.

<!-- BROKEN: hidden from screen readers, still tabbable -->
<div aria-hidden="true">
  <a href="/account">My account</a>
  <button>Save</button>
</div>

<!-- FIX A: modern, whole subtree removed from focus -->
<div aria-hidden="true" inert>
  <a href="/account">My account</a>
  <button>Save</button>
</div>

<!-- FIX B: per-control, wide browser support -->
<div aria-hidden="true">
  <a href="/account" tabindex="-1">My account</a>
  <button tabindex="-1" disabled>Save</button>
</div>

<!-- FIX C: if it should be gone entirely, drop aria-hidden -->
<div style="display:none">
  <a href="/account">My account</a>
</div>

When the panel becomes visible again, reverse the change: remove inert and aria-hidden together, and restore the original tabindex values so the controls return to the focus order.

False positives

This rule is precise, so genuine false positives are rare, but a few situations look like errors and are not. One is timing: if your script adds inert or sets tabindex="-1" a moment after rendering, a scanner that reads the initial DOM may flag the container before your code runs. Verify the live state in the browser.

Another is a child marked aria-hidden="false" inside a hidden parent. That does not re-expose the child, and it does not remove it from the focus order, so the warning still stands. Do not rely on a nested aria-hidden="false" to clear the issue.

FAQ

Is inert better than tabindex="-1"?

For a whole hidden subtree, yes. The inert attribute removes every descendant from focus and pointer interaction at once, so you do not have to track each control. It is now broadly supported; use tabindex="-1" plus disabled only where you must support older browsers.

Why not just keep aria-hidden and ignore the warning?

Because keyboard users still reach the control while screen readers stay silent on it. That is a real Level A failure, not cosmetic. The warning is pointing at a broken experience.

Does display:none also remove focus?

Yes. Both display:none and visibility:hidden take elements out of the accessibility tree and the focus order, which is why they often beat aria-hidden for content that should be fully gone.

What about a single decorative icon?

A decorative icon with aria-hidden="true" is fine, as long as it is not focusable and contains no focusable children. The rule only fires when a focusable element is involved.

Related reading: Required ARIA attributes must be provided, ARIA roles must conform to valid values, Buttons must have discernible text, and why machine-readable web standards matter for AI search.

Want every accessibility issue found and fixed?

An advanced SEO and accessibility audit catches focus mismatches like this across your whole site, with clear fixes you can hand to a developer.

Get an advanced SEO audit

Claude Vincent is a technical SEO consultant focused on crawlability, rendering, and AI-search visibility. He writes the field guides and case studies at SEO ProCheck, with a bias toward the durable, unglamorous work that decides whether search engines and AI answer engines can actually read and cite a site.

About SEO ProCheck

Technical SEO consulting and GEO strategy with 20 years of enterprise experience. Case studies, resources, and tools for search and AI visibility.

Work With Me

Technical SEO audits, GEO strategy, site migrations, and international SEO. Hourly consulting for teams who need hands-on support, not just reports.

Subscribe to our newsletter!

More from our blog