ARIA Hidden On A Focusable Element

ID

javascript.jsx_aria_hidden_focusable

Severity

high

Remediation Complexity

trivial

Remediation Risk

low

Remediation Effort

low

Resource

Reliability

Language

JavaScript

Tags

accessibility, jsx, reliability

Description

Reports aria-hidden="true" on a JSX element that still takes keyboard focus.

Rationale

aria-hidden removes an element from the accessibility tree but not from the tab order. A focusable element hidden this way becomes a focus trap with nothing to announce: the user tabs onto it, the screen reader has no node to read, and the keyboard focus appears to vanish. This is the one combination the ARIA specification calls out as never valid.

<button aria-hidden="true">Save</button>            // FLAW - reachable by Tab, unreadable there
<div tabIndex={0} aria-hidden="true" />             // FLAW - tabIndex puts it back in the order

<button aria-hidden="true" tabIndex={-1}>Save</button>  // OK - hidden and out of the order
<span aria-hidden="true">x</span>                       // OK - decoration, takes no focus
<button aria-hidden={collapsed}>Save</button>           // OK - computed, not judged here

Focusability is read as written, and the tabIndex decides when there is one: a negative tabIndex takes even a button out of the tab order — which is exactly the fix — while a non-negative one puts any element into it. With no tabIndex, the tag decides: the interactive controls, the links that carry an href, and the embedded-content tags.

Remediation

Add tabIndex={-1} so the element leaves the tab order along with the accessibility tree, or drop aria-hidden and hide the element with display: none or the hidden attribute, both of which remove it from both. If the element has to stay operable, give it an accessible name instead of hiding it.

© 2026 Xygeni. All rights reserved