Skip to main content

Search rules

Search all UI Guides rules by name, category, or source

interactionsARIA

Never aria-hidden Something Focusable

NEVER

NEVER: Put `aria-hidden="true"` (or `role="presentation"`) on a visible focusable element or a subtree that is still tabbable — it strips the a11y tree but NOT the tab order, so focus walks into a ghost: the ring travels off screen and the screen reader announces nothing. Use `inert` on the container (removes it from tab order, a11y tree and hit-testing at once) or unmount it.

Use inert or unmount to hide a subtree, so the tab order and the a11y tree agree

// ghost: <div aria-hidden="true" className="opacity-0"><button>Close</button></div>
<div inert={!open} className="opacity-0"><button>Close</button></div>

Bad

Good

Why it matters

aria-hidden="true" removes an element and its whole subtree from the accessibility tree. It does NOT remove anything from the tab order — those are two different trees, and this is the single most common way to desynchronise them. An off-canvas drawer hidden with aria-hidden plus opacity: 0 and a transform is still fully tabbable: keyboard focus walks into it, the focus ring travels off screen, and a screen reader announces nothing whatsoever, because the element it is focused on does not exist as far as the accessibility tree is concerned.

Focusing on "nothing" is a dead end no user can recover from. The correct tools remove the subtree from BOTH trees at once: unmount it, or set the inert attribute on the container — inert takes the subtree out of the tab order, out of the accessibility tree, and out of hit-testing in one attribute, which is why it also shows up in this corpus as the way to freeze the rest of the page during a drag.

If for some reason you must keep aria-hidden, you have to strip tabindex and disable every focusable descendant by hand, and keep doing so as the subtree changes — which is precisely the bookkeeping inert exists to delete.

Built by Gleb Stroganov, design engineer at Evil Martians.

The rules come from other people's skills and guidelines — Vercel, Rauno Freiberg, @Ibelick, impeccable, Emil Kowalski, Tailwind, RAMS — each one credited on the Sources page. The work here is extraction and wiring: every rule is pulled into one corpus, given a good and a bad example you can operate, a MUST/SHOULD/NEVER rule an agent can paste, and a link back to where it came from.