The 'blocked aria-hidden' warning is telling you the truth
Marcus Osei
A screen-reader user opens your modal, tabs to the close button, presses it, and the button they had focus on disappears into a region you just marked aria-hidden="true". The console lights up: Blocked aria-hidden on an element because its descendant retained focus. You silence the warning with a one-liner and ship. The user, meanwhile, is now focused on nothing — their virtual cursor has fallen into a hole in the page, and the next Tab press lands somewhere neither of you expected.
That is the situation Durgesh Rajubhai Pawar takes apart in a new CSS-Tricks piece published on August 12. The headline is deliberately provocative — "Blocked aria-hidden: The Warning is Right, and Every Fix You've Found is Wrong" — but the argument is calm and, if you own any modal code, worth reading before your next close-button PR.
What the browser is actually telling you
The warning fires in a specific shape: an element becomes aria-hidden while a descendant of it still holds focus. Pawar's point is that the browser is not being fussy about ARIA hygiene. It is warning you that a real user is about to be stranded, because a screen reader tracks focus, and you have just declared the thing focus lives inside to be invisible to it.
The bug is not the attribute. The bug is the order: focus is still inside the region at the moment the region is hidden.
Three workarounds that hide the problem, not fix it
Pawar names three fixes that keep making the rounds and calls each of them wrong for the same reason — they silence the warning without moving focus first.
The first is a blur() one-liner on the focused element. The console clears, because nothing is focused any more, but the user is left focused on the document body. Their next key press goes nowhere useful.
The second is wrapping the close call in setTimeout. This shuffles the sequence into a later tick, which sometimes hides the warning by accident, but the ordering — focused element, then hidden ancestor — is still exactly what the browser is complaining about. You have made a race condition, not a fix.
The third is stripping the aria-hidden attribute so the warning cannot fire. That does silence the console. It also removes the very signal you were adding to protect assistive-tech users from an overlay that is closing on top of them.
If a fix's only measurable effect is a quieter DevTools panel, it is not a fix.
Move focus before you hide the region
Pawar's rule is short enough to tape to a monitor: focus has to leave a region before that region becomes hidden or inert. Once you accept that, the fix is a re-ordering, not a new attribute.
His prescribed sequence, for an overlay closing back to the trigger that opened it, is:
- Un-inert the background — the rest of the page needs to accept focus again.
- Move focus to the element that opened the overlay (the trigger button).
- Apply
inertto the closing overlay, together withpointer-events: none.
Focus is out of the region before the region is switched off. The screen reader's virtual cursor lands on the trigger, which is exactly where the user's mental model already put it. No warning, because there is nothing to warn about.
Note the other quiet change here: Pawar uses the inert attribute on the closing shell, not aria-hidden. inert removes the whole subtree from focus, from click targets, and from the accessibility tree in one attribute. aria-hidden only does the accessibility-tree part, which is what got you into this in the first place. If you are still reaching for aria-hidden on interactive containers, use inert and delete a lot of glue code.
The shorter route: let the platform run the dance
The other move Pawar recommends, where you can take it, is to stop rolling your own modal at all. Migrate to the native <dialog> element, open it with .showModal(), and the browser handles the focus dance for you: focus is moved into the dialog on open, trapped there for the lifetime of the modal, and returned to the invoking element on close.
That is the "use the platform" answer. Every step in the three-step sequence above is a step the browser already knows how to take on your behalf. If your only reason for a hand-rolled overlay is that you needed a custom shell around a form, wrap that shell in <dialog> and let the element carry the a11y contract.
The verdict
The "blocked aria-hidden" warning is not noise. It is the browser telling you a screen-reader user is about to lose their place. Every popular workaround Pawar lists silences the warning by making the underlying bug less visible, which is the opposite of the trade you want.
Before your next PR touches a modal or an overlay:
- Move focus out of the region before you hide, inert, or unmount it.
- On close, un-inert the background, focus the trigger, then apply
inertto the closing shell. - Prefer
inerttoaria-hiddenfor interactive containers you are switching off. - If you can, delete the custom modal and open a
<dialog>with.showModal(). That is one fewer contract for you to maintain and one more the browser holds for you.
Source: CSS-Tricks (css-tricks.com)