aria-hidden and focusable elements: a common screen reader trap
Do not put aria-hidden="true" on a link, button or form field, or on a container that holds one. The attribute removes an element from what screen readers expose, but it leaves the element in the Tab order, so a keyboard user can land on a control that assistive technology has been told is not there. To take something out of use for everyone, use the hidden attribute, display: none or inert.
Published . Last reviewed .
aria-hidden is an ARIA attribute that tells the browser to leave an element, and everything inside it, out of the accessibility tree, the structure screen readers read in place of the visual page. Keyboard focus is decided separately, by the tab order. An element with aria-hidden="true" can therefore disappear for a screen reader and still be the next stop when someone presses Tab. W3C's Accessibility Conformance Testing (ACT) rule for this case says it may confuse people who use assistive technology, and maps it to WCAG 4.1.2 Name, Role, Value.
MDN's aria-hidden reference states the rule plainly: do not use aria-hidden="true" on elements that can receive focus, or on a parent or ancestor of a focusable element, because every child inherits the attribute.
What aria-hidden does, and what it leaves alone
The WAI-ARIA 1.2 specification defines aria-hidden as indicating whether an element is exposed to an accessibility API, the interface browsers use to pass page information to assistive technology. It takes three values: true hides the element, false exposes it as if it were rendered, and leaving the attribute off lets the browser decide from whether the element is rendered. Five consequences matter here:
- It hides nothing from sight. MDN says the attribute hides content from assistive technology without visually hiding anything, so a sighted user still sees the element and can still click it.
- Children inherit it. An element is hidden if it or any ancestor is not rendered or has aria-hidden set to true. One attribute on a wrapper hides every link, button and field inside it.
- It cannot be undone further down. The specification says
aria-hidden="true"on a parent overridesaria-hidden="false"on its descendants (section 7.1), and it adds thatfalseis known to work inconsistently in browsers. - It does not take the element out of the tab order. W3C's ACT rule describes the problem: an element with
aria-hidden="true"can still be reached by sequential focus navigation, although it should be hidden. - Focus can bring it back. ARIA 1.2 says browsers must give an accessible object to an element that is currently focused, even when it or an ancestor has
aria-hidden="true"(section 7.2), and the ACT rule notes that some browsers leave such elements in the tree. What a screen reader announces then depends on the browser and the screen reader, so test with the ones your visitors use.
Four ways of hiding or deactivating an element compare like this:
| Method | Visible on screen? | In the accessibility tree? | In the tab order? |
|---|---|---|---|
aria-hidden="true" | Yes | No, though a focused element may still be exposed | Yes, if the element can take focus |
hidden attribute | No | No | No |
display: none in CSS | No | No | No |
inert attribute | Yes, and nothing changes visually by default | No | No |
The rows come from ARIA 1.2, which excludes display: none, visibility: hidden and the hidden attribute from the tree, from the ACT rule, which notes that browsers show the hidden attribute as display: none and passes a link hidden with display: none, and from MDN's inert page, which says an inert element and its descendants cannot be focused or clicked.
How a focusable element ends up hidden
W3C's ACT rule, "Element with aria-hidden has no content in sequential focus navigation", checks that nothing inside an aria-hidden element is both focusable and in the tab order. Because both conditions must hold, an element with a negative tabindex or the disabled attribute passes, and even a paragraph fails if it has tabindex="0".
| Case | Outcome | Why |
|---|---|---|
A link inside an aria-hidden wrapper, also hidden with display: none | Passes | A link hidden by CSS is not in the tab order. |
A disabled input with aria-hidden="true" | Passes | The disabled attribute takes it out of the tab order. |
A button with tabindex="-1" inside an aria-hidden wrapper | Passes | It can be focused, but it is not in sequential focus navigation. |
An svg with aria-hidden="true" inside a link | Passes | The hidden element holds nothing focusable. A focusable ancestor is not a problem. |
| A link inside an aria-hidden wrapper, positioned far off screen | Fails | Off screen is not hidden. The link is still in the tab order. |
An input with aria-disabled="true" inside an aria-hidden wrapper | Fails | It was disabled with ARIA only, so it is still focusable. |
A button inside aria-hidden="false", inside aria-hidden="true" | Fails | The ancestor's true cannot be reset, and the button takes focus. |
W3C maps a failed outcome to the criterion not being satisfied and a passed outcome to "needs further testing", so a pass on this rule does not show that a page meets 4.1.2. Typical ways the problem arises:
- A control hidden with the attribute alone. A link or button gets
aria-hidden="true"to keep it out of the screen reader's view while a keyboard user can still Tab to it. - A closed menu or drawer that is only moved off screen. The links inside stay in the tab order, which is the off-screen case in the table. See accessible navigation menus.
- Slides and panels that are not showing. Carousel slides, tab panels and accordion panels get aria-hidden on a wrapper while their links stay reachable. See accessible carousels and accessible accordions and tabs.
- The page behind a modal dialog. A script sets aria-hidden on the page wrapper when a dialog opens, but nothing stops Tab from reaching the page. The ARIA Authoring Practices Guide (APG) pattern says aria-modal replaced aria-hidden for telling assistive technology that outside content is inert. Where aria-hidden is still used, APG says it is important to set it on each element that holds part of the inert layer and to keep the dialog out of any element that has aria-hidden. See accessible modal dialogs.
- State that changes. A script sets aria-hidden when something closes and leaves it when the thing opens again. The ACT rule assumes that interacting with the page does not change the attribute, so a check of one state says nothing about the others. Test each state.
Which WCAG criteria are involved
4.1.2 Name, Role, Value (Level A). The ACT rule maps to this criterion. W3C's Understanding page for 4.1.2 says its intent is that assistive technology can gather information about a control, activate it and keep up to date on it, and it singles out focus as a particularly important state. In our reading, a control that has focus while assistive technology has been told it is hidden works against that. The page lists no failure technique for it, so the ACT rule is the clearest W3C test.
1.3.1 Info and Relationships (Level A), when the hidden content is visible. ARIA 1.2 allows aria-hidden on visible content only with caution, to remove redundant or extraneous content, and says authors must keep identical or equivalent meaning and functionality available to assistive technology. Its own warning shows the cost: if the visible link text "Go to checkout" is hidden and "Check out now" is exposed instead, a voice control user who says what they see may be unable to reach the link. In our reading, a visible label, heading or error message hidden this way with no equivalent is information shown on screen but missing from the code, which is what our WCAG 1.3.1 page covers.
What to use instead
- Decorative or repeated content with nothing focusable in it: keep aria-hidden. An icon beside visible text is the standard case, and MDN's example hides an icon inside a button so that it does not become part of the button's accessible name. W3C's test cases pass an svg with aria-hidden inside a link. See SVG accessibility and alt text for icons.
- Content nobody should reach right now:
hiddenordisplay: none. A closed menu, a collapsed panel or a slide that is not showing should leave sight, the tree and the tab order together, and both options do. Toggle the attribute from script when the state changes, and check that no CSS display rule on the same element overrides it: the ACT rule notes that doing so can reveal an element that has the hidden attribute. - Visible content that must not be used right now:
inertor a native dialog. The page behind a modal is the usual case. MDN lists inert as available across browsers since April 2023, and says a dialog opened withshowModal()makes the rest of the page inert for you (MDN's dialog page). Inert content looks the same by default, and MDN says it is the author's job to show which parts are active, so dim or style the inert part yourself. - One control that should not work:
disabled. MDN suggests the disabled attribute with:disabledstyles for an individual control, and inert for sections of content. - A duplicate link to the same place: make it one link. W3C's technique H2 puts an image and its text in one
aelement with empty alt text on the image, so a keyboard user meets one link and a list of links has no duplicate. If two links stay, one option is aria-hidden together withtabindex="-1"on the duplicate: W3C's ACT rule passes a button set up that way, because it is not in sequential focus navigation. In our reading, two cautions apply: ARIA 1.2 says an element with a negative tabindex can still be focused by script or a mouse click, and the visible link beside it has to do the same job.
Two short examples, the first keeping aria-hidden where it belongs and the second swapping it for the hidden attribute on a closed drawer:
<button type="button">
<svg aria-hidden="true" viewBox="0 0 24 24">...</svg>
Download report
</button>
<!-- Trap: the drawer class moves it off screen, but the link still takes Tab -->
<div class="drawer" aria-hidden="true">
<a href="/shop/">Shop</a>
</div>
<!-- Fix: hidden until a script opens it -->
<div class="drawer" hidden>
<a href="/shop/">Shop</a>
</div>
W3C's older Using ARIA note listed this as its fourth rule of ARIA use; it is a discontinued draft kept for reference. For when ARIA helps at all, see ARIA basics.
Check it yourself
Three steps, no special software:
- Press Tab in every state. Go through the page with the menu closed and open, the dialog closed and open, and each slide or panel. Watch for focus that vanishes or stops on something you cannot see. The keyboard accessibility test sets out the full routine, and focus indicators explains what you should see at each stop.
- Search the code for aria-hidden. In your browser's developer tools, search the element inspector for
aria-hidden. For each hit, ask whether the element, or anything inside it, is a link with an href, a button, a form field, asummaryor an element with a tabindex of 0 or more. If it is, and it is not also hidden withhiddenordisplay: none, it is a candidate. - Listen to the candidates. With a screen reader running, Tab to each one and note what is announced, if anything. Results vary between browsers and screen readers, so see how screen readers read a page. For tabindex problems, see focus order and tabindex.
Two free tools cover part of this. The accessibility bookmarklet reads the page as your browser has rendered it, content added by a script included, and "Run the checks again" re-reads it after you open a menu. It does not flag aria-hidden on focusable elements, and it presses no keys. It does leave aria-hidden content out when it works out a name, so a link or button whose only content is hidden that way is reported as having no accessible name, a symptom worth following up.
Scan my site for free runs rule-based checks on the HTML your server sends, and one flags aria-hidden on a link with an href, a button, a form field or an element with a tabindex of 0 or more, whether the attribute is on the element or an ancestor. Like W3C's test cases, it leaves out controls with a negative tabindex or the disabled attribute. It also skips controls inside an aria-hidden dialog or panel marked as a popup (a dialog element, role="dialog", aria-modal or a class such as modal or drawer), so it would not flag the drawer example above. It cannot see a state a script sets after the page loads. What we check lists every rule. For the wider routine, see how to make a website accessible.
Keep it checked
A script, a theme update or a redesign can leave aria-hidden on a control that used to be fine. GotAlt checks the pages you monitor every week. It compares each image's alt text with the image itself (up to six images per page), runs its rule checks, opens monitored pages in a browser for contrast and other checks that need a rendered page (see what we check), and reports what changed. Plans are from $69 a month. Audit my whole site from $69/mo.
aria-hidden and focus questions
What happens when a focusable element has aria-hidden="true"?
The element leaves the accessibility tree, so screen readers are told it is not there, but it stays in the tab order, so keyboard users can still land on it. W3C's ACT rule describes this as confusing for assistive technology users, and ARIA 1.2 says a browser must expose an element that is currently focused even if it has aria-hidden. Behavior varies by browser and screen reader.
Does aria-hidden remove an element from the tab order?
No. aria-hidden changes only what is exposed to assistive technology. It does not stop an element from receiving keyboard focus, and it hides nothing visually. To remove an element from the tab order, hide it with the hidden attribute or display: none, make it inert, or disable a single control. A tabindex of -1 also leaves the tab order, but a click or a script can still focus the element.
How do I hide something from screen readers and keyboard users at the same time?
Hide it for everyone. The hidden attribute and CSS display: none remove an element from sight, the accessibility tree and the tab order together. For content that stays visible but should not be used, such as the page behind a modal dialog, use the inert attribute or a native dialog opened with showModal(). Do not rely on aria-hidden alone.
Is it okay to use aria-hidden on an icon inside a button or link?
Yes, when the icon has nothing focusable inside it and the button or link keeps its own visible text or accessible name. MDN's example hides an icon inside a button this way, and W3C's ACT rule passes an svg with aria-hidden inside a link, because the problem arises only when the hidden element contains something focusable.
What is the difference between aria-hidden and inert?
aria-hidden only removes an element from the accessibility tree. The content stays visible, clickable and focusable. The inert attribute makes an element and everything inside it unfocusable and unclickable and removes it from the tab order and the accessibility tree, but it does not change how the content looks, so you need to dim or style it yourself. MDN lists inert as available across browsers since April 2023.
Should I use aria-hidden on the page behind a modal dialog?
Not on its own. It hides the page from screen readers but does not stop Tab from reaching it. The ARIA Authoring Practices Guide says aria-modal replaced aria-hidden for telling assistive technology that outside content is inert, and an HTML dialog opened with showModal() makes the rest of the page inert. Where aria-hidden is still used, APG says to set it on each element that holds part of the inert layer and to keep the dialog out of any aria-hidden ancestor.
Does aria-hidden="false" make a hidden element available to screen readers again?
Not reliably. ARIA 1.2 says aria-hidden="true" on a parent overrides aria-hidden="false" on its descendants, and notes that false is known to work inconsistently in browsers. W3C's ACT rule fails a button inside aria-hidden="false" that sits inside aria-hidden="true". To expose content, remove the attribute from the ancestor instead.
Which WCAG criterion does aria-hidden on a focusable element fail?
W3C's ACT rule for it maps to 4.1.2 Name, Role, Value (Level A) and treats a failed outcome as the criterion not being satisfied. The Understanding page for 4.1.2 lists no named failure technique for it, so the ACT rule is the clearest W3C test. Hiding visible content that carries meaning can also raise 1.3.1 Info and Relationships, in our reading.
Run the automated part first
The free scan runs 16 rule-based checks on your page's HTML, including aria-hidden on links, buttons and form fields. It cannot press keys or see a state a script sets later, so use the steps above for the rest. No signup.
Scan my site for freeRelated guides
- How to make a website accessible: the 10-step plan these guides build on.
- Touch target size: the 24 by 24 pixel rule in WCAG 2.2.
- CAPTCHA accessibility: why most CAPTCHAs exclude people, and the alternatives.
- Accessible forms: labels, instructions and errors.
- Form error messages: identifying errors and suggesting fixes.
- Buttons vs links: which to use and why it matters.
- Accessible modal dialogs: focus that moves in, stays and comes back.
- Accessible navigation menus: menus and mega menus that work by keyboard.
- Accessible carousels: controls, pausing and hidden slides.
- Accordions, tabs and disclosures: the patterns and the native details element.
- ARIA basics: the first rule of ARIA and when not to use it.