skip to content

What does the HTML inert attribute do to the subtree it is set on, and which bug does it fix that hiding the background visually or with aria-hidden does not?

level: seniorimportance: should knowfreq 38%

answer

  1. visible but switched off
  2. kills Tab, clicks, selection, find-in-page
  3. also removed from the accessibility tree
  4. aria-hidden alone leaves focus reachable
  5. boolean — the value never matters

basics

~20 s

inert makes an element and everything inside it non-interactive: the subtree cannot be focused by Tab or programmatically, does not respond to clicks, is not selectable or findable by find-in-page, and is hidden from assistive technology. It fixes background content behind a modal that is dimmed but still reachable by keyboard.

solid answer

~50 s

`inert` is a boolean global attribute that switches off an entire subtree. Elements inside cannot be focused — neither by tabbing nor by calling `focus()` — they do not fire click or activation events, their text cannot be selected or found with find-in-page, and the whole subtree is removed from the accessibility tree. The bug it solves is the classic modal defect: the page behind an open dialog is visually dimmed, but Tab still walks into it and a screen reader still reads it. `aria-hidden` on the background hides it from assistive technology while leaving it keyboard-focusable, which is the worst combination — focus lands on a node the screen reader has been told does not exist. Hiding the background with `display: none` fixes interaction but you can no longer see it. `inert` keeps content visible and inert at once. Note that a modal opened with `<dialog>`'s `showModal()` applies this state to everything outside the dialog for you.

go deeper

for a junior

Know that inert switches off an entire subtree — no focus, no clicks, hidden from screen readers — while the content stays visible on screen.

for a middle

List the effects precisely, including that programmatic focus() also fails and that the subtree leaves the accessibility tree, and note that inert is a boolean attribute.

for a senior

Diagnose the modal bug from symptoms — Tab escaping behind an overlay, a screen reader reading dimmed content — and explain why aria-hidden alone makes it worse rather than better.

for a principal

Push the team to the native primitive first: a modal <dialog> gives inertness, the top layer and focus handling together, so hand-rolled overlays should need justification rather than being the default.

## The problem Open a modal built by hand. The overlay dims the page and the dialog takes focus. Now press Tab a few times: focus walks out of the dialog and into the links and buttons behind the overlay, which are still perfectly focusable — the user is now typing into a form they cannot see. A screen-reader user has the same experience, wandering through page content that is visually "gone". The patches people reach for each fix half of it: - **Dimming with an overlay** fixes nothing; it is purely visual. - **`aria-hidden="true"` on the background** hides it from assistive technology but leaves everything focusable. This produces the worst state of all: focus lands on an element the screen reader has been told is not there, so the user hears nothing while their focus has moved. - **`display: none` on the background** genuinely removes interaction and accessibility exposure, but the background is now invisible, which defeats the point of a modal overlay. - **A JavaScript focus trap** works but is yours to write, maintain and get right in every edge case. ## What inert does `inert` is a boolean global attribute. Applied to an element, it puts that element **and its entire subtree** into an inert state: ```html <main inert>…the page behind the modal…</main> <div role="dialog" aria-modal="true">…</div> ``` In that state the subtree: - is skipped by sequential focus navigation, so Tab never enters it; - cannot be focused programmatically either — calling `focus()` on a node inside does nothing, which is what makes it stronger than removing elements from the tab order; - does not fire click or other activation events, so pointer interaction is dead; - is not editable and its text is not selectable; - is skipped by find-in-page; - is exposed to assistive technology as not present. That combination is exactly "visible but switched off", and nothing else in the platform gives you all of it declaratively. ## The boolean trap `inert` is a **boolean attribute**, so its value is irrelevant — presence is everything. `inert="false"` still makes the element inert. The only way to turn it off is to remove the attribute: ```js el.inert = false; // reflects the property; removes the attribute el.removeAttribute("inert"); // equivalent ``` And inertness is not overridable from below: there is no way for a descendant to opt out of an inert ancestor. If you need part of a subtree live, the inert boundary has to move up or split. ## Where you do not need it A `<dialog>` opened with `showModal()` puts everything outside the dialog into this same inert state automatically, and it is placed in the top layer above the rest of the page. That is the strongest argument for using the native element rather than assembling a modal out of divs: the behaviour you would otherwise be hand-rolling with `inert` plus a focus trap plus overlay stacking comes for free, and it is the same first-rule-of-ARIA reasoning that applies everywhere in HTML — use the native thing before you reproduce its behaviour. Other genuine uses of the attribute: off-canvas navigation drawers that slide out but remain in the DOM, carousel slides that are rendered but off-screen, and multi-step wizards that keep completed steps visible but frozen. ## What it is not `inert` is not a security boundary and not a substitute for `disabled`. A disabled form control is excluded from form submission and is styleable as disabled; an inert subtree's controls are merely unreachable — their values are still submitted with the form. It also does not hide anything visually. And it is not a replacement for correct focus *placement*: something still has to move focus into the dialog when it opens and back to the trigger when it closes.

  • Why is aria-hidden="true" on the background behind a modal actively harmful rather than merely insufficient?
    Because it desynchronises focus from the accessibility tree. The elements stay focusable, so Tab still moves into them, but the screen reader has been told they do not exist — the user's focus is somewhere they cannot perceive and nothing is announced. An incomplete fix that creates a silent focus state is worse than leaving the background exposed.
  • If you use <dialog> with showModal(), do you still need to set inert yourself?
    No. A modal `<dialog>` puts everything outside it into the inert state for you and renders in the top layer, so background content is unreachable by keyboard, pointer and assistive technology without any extra attribute. Setting `inert` manually is for the cases the native element does not cover, such as an off-canvas drawer or a frozen wizard step.
  • Are form controls inside an inert subtree excluded from form submission?
    No. Inertness makes them unreachable, not disabled — their names and values are still serialised on submit. Only `disabled` removes a control from the submitted data. If a step of a form must not contribute values, disable its controls or its `<fieldset>`; `inert` is about interaction and accessibility exposure, not about form participation.

saying these in an interview costs you the question

  • Says inert="false" turns inertness off
  • Thinks aria-hidden also prevents keyboard focus
  • Believes inert hides content visually
  • Uses inert instead of disabled on form controls
  • Adds inert around a native modal dialog needlessly

context