Every interface with hidden or blocked regions has had the same bug at some point: a keyboard user presses Tab and lands on a link inside a closed off-canvas menu, or a screen reader announces a button sitting behind an open overlay. The traditional fix was a pile of workarounds, such as tabindex="-1" on every focusable descendant, aria-hidden="true" on the container, a JavaScript focus trap, and a pointer-events rule in CSS. The inert attribute collapses that pile into one boolean attribute that the browser enforces for you.

What inert Does

Setting inert on an element makes the element and all of its descendants non-interactive. According to MDN, that has several effects at once:

  • The elements cannot receive focus or be the target of click events.
  • The content is excluded from find-in-page.
  • Text inside cannot be selected.
  • Editable fields and contenteditable regions cannot be edited.
  • The subtree is hidden from the accessibility tree, so screen readers do not discover or announce it.

The web.dev guide to inert describes the same behavior as blocking focus and click events, with the matching block on discoverability for assistive technology.

Baseline Status

inert shipped in Chrome 102 and Safari 15.5, and Firefox 112 completed cross-engine support in April 2023, which is when it reached Baseline Newly Available. MDN now lists it as Widely Available, having been available across browsers since that April 2023 date. The common shorthand that it has been “Widely Available since 2023” blurs the two tiers: it became interoperable in 2023 and crossed the Widely Available threshold later, once it had been in all major engines for roughly thirty months. For any site serving current browsers, the distinction no longer affects your decision. You can use it without a fallback.

Why It Replaces the Older Workarounds

Each of the older techniques solved part of the problem.

aria-hidden="true" hides content from assistive technology but does nothing to keyboard focus. If the container holds a link or button, keyboard users can still tab to it while the screen reader says nothing, which is worse than either failing alone. Lighthouse flags this as a failure.

tabindex="-1" removes an element from the tab order, but you have to apply it to every focusable descendant and then remember to undo it, including for elements added later. It also leaves the content in the accessibility tree and leaves the pointer working.

The disabled attribute remains the right tool for a single form control. It is not designed for a region containing links, headings, and text.

inert handles the whole subtree at once, for focus, pointer, and assistive technology, and restoring interactivity means removing one attribute. The same rule covers content you add to the subtree later, because the attribute belongs to the ancestor.

Three Patterns

An off-canvas menu

A drawer that slides in from the side is usually hidden with a transform, which leaves its links in the tab order while off screen. Mark it inert while it is closed:

<button id="menu-toggle" aria-expanded="false" aria-controls="drawer">Menu</button>

<nav id="drawer" class="drawer" aria-label="Site" inert>
  <a href="/css/">CSS</a>
  <a href="/accessibility/">Accessibility</a>
</nav>

<main id="page">...</main>
.drawer {
  position: fixed;
  inset: 0 auto 0 0;
  transform: translateX(-100%);
  transition: transform 0.25s ease;
}
.drawer:not([inert]) {
  transform: none;
}
const toggle = document.getElementById("menu-toggle");
const drawer = document.getElementById("drawer");
const page = document.getElementById("page");

function setOpen(open) {
  drawer.inert = !open;
  page.inert = open;
  toggle.setAttribute("aria-expanded", String(open));
  if (open) drawer.querySelector("a").focus();
}

toggle.addEventListener("click", () => setOpen(drawer.inert));
document.addEventListener("keydown", (e) => {
  if (e.key === "Escape" && !drawer.inert) {
    setOpen(false);
    toggle.focus();
  }
});

While the drawer is closed, nothing inside it can be reached. While it is open, the main content is inert, so focus cannot wander behind the panel. The toggle button sits outside both regions and stays operable. Note that the script moves focus explicitly on open and on close; inert blocks interaction but does not choose where focus goes next.

A modal overlay

For a real modal, use <dialog> with showModal() and skip manual work. Per MDN, everything outside a modal dialog becomes inert automatically. Reach for inert yourself only when you are building an overlay that cannot be a <dialog>, for example a legacy component or a custom panel. In that case, set inert on the siblings of the overlay, never on its ancestors, since the attribute would disable the overlay too.

A busy state

During a form submission or a long save, marking a wrapper inert stops double clicks and stray edits:

form.closest(".panel").inert = true;
await save();
form.closest(".panel").inert = false;

Pair this with a visible status message placed outside the inert region, so that screen reader users are told why the form stopped responding.

Pitfalls

There is no built-in visual cue. MDN states plainly that browsers provide no default styling for inert content, so you must show users which parts are inactive. The web.dev guidance suggests reduced opacity and a default cursor on [inert] elements. Without this, an inert region looks identical to a broken one.

Focus can be lost. If the element that currently has focus becomes inert, the user loses their place. Move focus deliberately to an element that stays active, as the drawer example does.

Hidden content still needs an honest label. inert removes the subtree from assistive technology, which means you should not use it to hide content that users still need to read. Use it for regions that are off screen or temporarily unavailable, and put any explanation in a region that remains active.

Do not stack it on dialogs you open with showModal(). The browser already makes the rest of the page inert for you.

The practical upgrade path is a short audit. Search your code for aria-hidden paired with manual tabindex changes, and for focus-trap libraries used to guard closed drawers or background content. In most cases you can delete the workaround, set inert on the region that should be unreachable, add a visual style for [inert], and test once with the keyboard and once with a screen reader.