Who it affects
Someone using a screen reader to buy museum tickets presses Tab, lands on something, and the screen reader goes quiet. They cannot tell if it is a button, a link or a bug, so they press Enter and hope.
Someone navigating a slideshow with the keyboard Tabs through the links on all six hidden slides before reaching the next visible control.
The site's own developer cannot reproduce the complaint, because with a mouse the hidden panel is simply not there.
Broken versus fixed
Both examples are live and rendered in a sandboxed frame. The broken one is deliberately broken.
Tab stops on Join now. A screen reader announces nothing, because aria-hidden has removed the button from what it can see.
The panel is hidden from everyone until it is opened. Tab goes from the paragraph to the Plan your visit link, and the screen reader has nothing silent to land on.
Show the markup behind both examples
<style>body{font-family:system-ui;margin:0;padding:12px;font-size:14px}.panel{opacity:.35;border:1px dashed #999;padding:8px;margin:8px 0}button{font:inherit;padding:4px 10px}p{margin:0 0 6px}</style>
<p>Click here, then press Tab. The faded buttons take focus even though screen readers are told they do not exist.</p>
<div class="panel" aria-hidden="true">
<p>Members get free entry this weekend.</p>
<button type="button">Join now</button> <button type="button">Not today</button>
</div>
<p><a href="#">Plan your visit</a></p>
<style>body{font-family:system-ui;margin:0;padding:12px;font-size:14px}.panel{border:1px dashed #999;padding:8px;margin:8px 0}button{font:inherit;padding:4px 10px}p{margin:0 0 6px}</style>
<p>Click here, then press Tab. The closed panel is hidden from everyone, so focus goes straight to the link.</p>
<div class="panel" hidden>
<p>Members get free entry this weekend.</p>
<button type="button">Join now</button> <button type="button">Not today</button>
</div>
<p><a href="#">Plan your visit</a></p>
Test it by hand in two minutes
- Press Tab repeatedly through the whole page. Each stop should be visible. A stop where nothing appears to have focus is the bug.
- In the Elements panel, search for aria-hidden="true". Inside each match look for a, button, input, select, textarea or anything with tabindex.
- Run a screen reader and Tab through. A silent Tab stop, or one that announces only blank, is an aria-hidden element with focus inside.
- Open and close the menu or modal with the keyboard and check the closed version takes no Tab stops.
The fix
<div class="drawer" aria-hidden="true">
<a href="/tickets">Tickets</a>
</div>
<div class="drawer" hidden>
<a href="/tickets">Tickets</a>
</div>
If the element is closed, hide it fully. The hidden attribute (or display:none) removes it from both the screen reader and the Tab order, so aria-hidden is no longer needed.
Page behind an open modal
<main aria-hidden="true">...</main>
<div role="dialog" aria-modal="true">...</div>
<main inert>...</main>
<div role="dialog" aria-modal="true">...</div>
inert makes the element and everything inside it unfocusable and hidden from assistive technology in one go. All current browsers support it.
Off-screen slide in a carousel
<li class="slide" aria-hidden="true"><a href="/exhibit">Roman coins</a></li>
<li class="slide" aria-hidden="true"><a href="/exhibit" tabindex="-1">Roman coins</a></li>
If the slide must stay in the page for the animation, give each focusable thing inside tabindex="-1" while the slide is not the current one, and remove it when it is.
Common mistakes
- Hiding a panel with opacity: 0 or by moving it off screen; both keep it in the Tab order.
- Putting aria-hidden="true" on the body or main element to trap focus in a modal, then forgetting to remove it when the modal closes.
- Adding aria-hidden to an icon button because the icon is decorative. Put it on the icon, not the button.
- Using visibility:hidden on a parent and visibility:visible on a child, which makes the child focusable again.
WCAG criteria this rule maps to
axe-core tags this rule as WCAG 2.2 level A. It is one of the checks for:
- 4.1.2 Name, Role, Value (level A). Official W3C text.
The scanner finds every element with aria-hidden="true" and checks whether it, or anything inside it, can take keyboard focus. It cannot tell whether the element is meant to be hidden right now or is a closed state that will open later; both need the same fix. Automated tools find only part of the accessibility problems on a page; a pass on this rule is not a pass on the criterion.
Related rules
aria-hidden-body
aria-hidden="true" tells assistive technology to ignore an element and everything inside it.
A
Frames with controls inside must not have tabindex=-1
frame-focusable-content
An iframe with tabindex="-1" is taken out of the Tab order, and so is everything inside it.
A
Scrollable areas must be reachable with a keyboard
scrollable-region-focusable
When a box has its own scrollbar, mouse users scroll it with the wheel.
A
Do not put one control inside another
nested-interactive
A button, a tab, a switch and similar controls are announced as one thing; whatever is inside them is treated as their label, not as separate controls.