inert: Disable an Entire Section of the Page in One Attribute
Focus trapping used to be one of the genuinely hard parts of building modals by hand: intercept Tab at the ends, loop it around, catch programmatic focus escapes, hide the background from screen readers with aria-hidden - and get every edge case slightly wrong. The platform answer is one attribute on the background instead of a trap on the modal:
function openDrawer() {
drawer.hidden = false;
main.inert = true; // everything in main: unclickable, unfocusable, unreadable
drawer.querySelector('input, button, a')?.focus();
}
function closeDrawer() {
main.inert = false;
drawer.hidden = true;
lastTrigger?.focus(); // put focus back where the user was
}
An inert subtree can't be clicked, can't receive focus, is skipped by Tab, is invisible to screen readers, and its text can't even be found with Ctrl+F. It's disabled for arbitrary DOM regions. Focus doesn't need trapping in the drawer - there's simply nowhere else focusable to go.
Where it beats the alternatives
vs aria-hidden="true": aria-hidden hides from assistive tech but leaves elements clickable and tabbable for everyone else - you needed it plus a focus trap plus pointer-events. inert is all three behaviors in one, kept in sync by definition.
vs the dialog element: showModal() gives you this for free - the rest of the document becomes inert automatically. Use inert directly when your overlay isn't a dialog: slide-out drawers, custom sheets, in-place editing modes.
The other use cases
<!-- A form section that's not applicable until an option is chosen -->
<fieldset inert class="dimmed">...shipping address...</fieldset>
<!-- Content that's loading - visible skeleton, but not interactive -->
<section inert aria-busy="true">...stale results while refetching...</section>
<!-- Off-screen carousel slides that shouldn't be tabbable -->
<div class="slide" inert>...</div>
That carousel case fixes a real accessibility bug in most hand-rolled sliders: keyboard users tab into slides that are visually off-screen and the page scrolls to nowhere. Toggle inert as slides enter and leave view (an IntersectionObserver does it neatly).
Notes
- Style it - inert applies no visual change.
[inert] { opacity: 0.5; }or a blur communicates the state sighted users can't otherwise perceive. - It's all-or-nothing for the subtree; there's no un-inerting a child inside an inert parent. Structure your layout so overlay and background are siblings.
- Support: Chrome 102+, Firefox 112+, Safari 15.5+ - safely universal now.
Modal correctness went from a library problem to two lines of platform. If you still ship a focus-trap dependency, this is your sign to delete it.
Full-stack web developer sharing practical tutorials and building tools that ship.
Got something on your mind?
My inbox is open - no forms disappearing into the void here.
- Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
- Hire me for a project Have something custom in mind? Let's talk scope and timelines.
- Product support Bought something here? I'll help you get it running.
I usually reply within 1-2 business days.