Sheath rule
a11y-no-aria-hidden-on-focusable
Elements with
aria-hidden="true" must not be focusable or contain focusable descendants.
- Package
- Core
- Category
- Accessibility
- Default severity
- error by default
- Auto-fix
- Auto-fix available
with --dangerous (the fix removes the attribute)
#Why
Using aria-hidden="true" on an element that can receive focus creates a confusing experience for screen reader users. The element is hidden from the accessibility tree but can still be reached via keyboard navigation, creating a "ghost" element that users can interact with but cannot understand.
The same problem applies to every descendant because aria-hidden removes the
whole subtree from the accessibility tree. A descendant cannot undo an
ancestor's aria-hidden="true" by setting aria-hidden="false".
#Examples
#Bad
<!-- Focusable elements with aria-hidden -->
<button aria-hidden="true">Hidden Button</button>
<a href="/page" aria-hidden="true">Hidden Link</a>
<input type="text" aria-hidden="true">
<select aria-hidden="true"><option>Option</option></select>
<!-- Elements made focusable via tabindex -->
<div aria-hidden="true" tabindex="0">Focusable div</div>
<span aria-hidden="true" tabindex="0">Focusable span</span>
<!-- Contenteditable with aria-hidden -->
<div aria-hidden="true" contenteditable="true">Editable content</div>
<div aria-hidden="true" contenteditable="plaintext-only">Editable content</div>
<!-- Focusable descendants are hidden too -->
<div aria-hidden="true">
<button>Hidden descendant</button>
</div>
#Good
<!-- Hidden and not focusable -->
<div aria-hidden="true">Decorative content</div>
<span aria-hidden="true"><i class="icon"></i></span>
<!-- Focusable but not hidden -->
<button>Visible Button</button>
<a href="/page">Visible Link</a>
<!-- Disabled elements are not focusable -->
<button aria-hidden="true" disabled>Disabled button</button>
<!-- Hidden inputs are not focusable -->
<input type="hidden" aria-hidden="true" name="context" value="checkout">
<!-- Links without href are not focusable -->
<a aria-hidden="true">Not a link</a>
<!-- Negative tabindex is the sanctioned remediation: it takes the native
control out of the tab order, matching what aria-hidden promises -->
<button aria-hidden="true" tabindex="-1">Decorative button</button>
<a href="/page" aria-hidden="true" tabindex="-1">Hidden link</a>
<!-- Every descendant is outside sequential focus navigation -->
<div aria-hidden="true">
<button disabled>Disabled button</button>
<a href="/page" tabindex="-1">Hidden link</a>
</div>
#Focusable Elements
These elements are focusable by default:
<a>(with href)<area>(with href)<button><input><select><textarea><details>and the first<summary>child that acts as its disclosure control<audio>/<video>(with controls)<iframe>- Elements with
tabindex="0"or positive tabindex - Elements with
contenteditable="true",contenteditable="plaintext-only", or an emptycontenteditable
#Notes
display: noneandvisibility: hiddenremove the element from the page and the accessibility tree together, so focus cannot reach it- Disabled form controls (
button,input,select, andtextarea) are not focusable, soaria-hiddenis safe on them. Adisabledattribute has no such effect on links or arbitrary elements - Hidden inputs are not focusable.
tabindexfollows HTML integer parsing, so leading ASCII whitespace is ignored and a numeric prefix such as the1in1.5still determines focusability - An explicit negative
tabindex(-1,-2, ...) on a natively focusable element removes it from the tab order, soaria-hiddenis safe there too. This pairing correctly hides a decorative control - A standalone
<summary>, or a later<summary>after an unconditional first summary child, is not a native disclosure control. An explicit nonnegativetabindexcan still make it focusable. - For interactive elements, use the
disabledattribute, addtabindex="-1", or remove thehreffrom links
#References
- WAI-ARIA: aria-hidden - Specification for aria-hidden state
- Deque University: aria-hidden-focus - Why aria-hidden content must not remain focusable
#Related Rules
- a11y-no-positive-tabindex - Tab order concerns