Imagine a two-step checkout. While the address is being validated, the payment section is visible but temporarily unavailable. It contains inputs, links, buttons, and perhaps a custom control. Disabling each control separately is easy to get wrong.

The inert attribute gives the browser the state of the region, not a list of controls to patch. It is a boolean global attribute, so it can sit on any HTML element that owns a meaningful section.

What inert changes

An inert element and its flat-tree descendants cannot receive focus or click events. Editable content cannot be edited. The browser treats the subtree as unavailable for text selection and normally ignores it during find-in-page. Assistive technologies do not receive it through the accessibility tree.

<section aria-labelledby="payment-title" inert>
  <h2 id="payment-title">Payment</h2>
  <label>
    Card number
    <input autocomplete="cc-number" />
  </label>
  <button>Pay now</button>
</section>

The heading is also absent from the accessibility tree while the section is inert. This is stronger than blocking pointer input. Use it only when the content itself should be unavailable, not when you merely want to prevent accidental clicks.

Toggle the property, not a collection of tabindex values

Dynamic interfaces still need a little JavaScript because application state decides when the section becomes available. Set the DOM property directly:

const payment = document.querySelector("#payment");

payment.inert = true;

validateAddress().then(() => {
  payment.inert = false;
});

Do not call setAttribute("inert", "false"). Boolean HTML attributes are true whenever they are present, regardless of their text value. Remove the attribute or set the inert property to false.

You must provide a visible cue too. The platform does not dim an inert region by default.

[inert] {
  opacity: 0.55;
}

@media (forced-colors: active) {
  [inert] {
    opacity: 1;
    outline: 0.2rem dashed currentColor;
  }
}

Opacity alone can be hard to perceive. Pair it with nearby status text such as "Checking address..." and update that text when the section becomes available.

Why pointer-events, aria-hidden, and disabled are different

pointer-events: none

Stops pointer hit testing. Keyboard focus and accessibility exposure remain.

aria-hidden="true"

Hides content from assistive technology. It does not prevent focus or clicks.

The disabled attribute is right for an individual form control. It does not apply to ordinary links, and putting it on an arbitrary container does nothing. A disabled <fieldset> can cover a group of form controls, but it has form-specific behavior and does not make every descendant type inert.

A home-grown loop that assigns tabindex="-1" only changes sequential focus. It must also remember previous values, watch for new descendants, block mouse input, and handle the accessibility tree. That is the custom machinery inert replaces.

Do not recreate native modal behavior

Opening a <dialog> with showModal() already makes the rest of the document inert. You should not add inert to every background section in that case. The browser owns the modal boundary and lets the active dialog escape ancestor inertness.

A custom drawer may be different. A non-modal navigation drawer should usually leave the page available. If the drawer must block the page, first ask whether it is really a modal dialog. Using <dialog> is safer than assembling inertness, focus movement, Escape handling, and focus restoration yourself.

If you still have a valid non-dialog case, keep the active surface outside the subtree you make inert. Otherwise you can disable the very close button the user needs.

Move focus before changing the state

If focus is currently inside a region, move it to a sensible active control before setting that region to inert. Do not leave the browser trying to recover from a focused element that suddenly became unavailable.

const editor = document.querySelector("#editor");
const resume = document.querySelector("#resume-editing");

resume.focus();
editor.inert = true;

Also avoid hiding important explanatory content inside an inert subtree. Someone using a screen reader will not hear it. Put the reason and the action needed to continue in the active region.

Primary references