inert is a Boolean global attribute. Its presence enables the behavior; writing inert="false" still enables it. In JavaScript, assign panel.inert = false or remove the attribute to restore interaction. MDN describes the attribute's behavior in its inert reference.
Put the unavailable area and its explanation in different containers
<button id="load" type="button">Load next shipment</button>
<p id="load-status" role="status" tabindex="-1"></p>
<section id="shipment" aria-labelledby="shipment-title">
<h2 id="shipment-title">Shipment SH-104</h2>
<p>North dock, 12 cartons.</p>
<button type="button">Edit shipment</button>
<a href="/shipments/SH-104">Open shipment record</a>
</section>
The load button remains outside the section, as does the status message. A status element inside an inert subtree would also become unavailable to assistive technology. Give the inert panel a visible state because the attribute supplies no default gray overlay or loading indicator:
#shipment[inert] {
opacity: 0.55;
}
The message should say what is happening rather than relying on dimming alone. Do not apply inert to a broad ancestor that also contains the message and the only way to recover from an error.
Move focus before making its current container inert
This helper supports a panel whose controls may already have focus. It deliberately restores focus only when that earlier control still exists and the user has not moved elsewhere:
const panel = document.querySelector('#shipment');
const loadButton = document.querySelector('#load');
const status = document.querySelector('#load-status');
let previousFocus;
function beginShipmentLoad() {
previousFocus = panel.contains(document.activeElement)
? document.activeElement : null;
if (previousFocus) status.focus();
panel.inert = true;
loadButton.disabled = true;
status.textContent = 'Loading the next shipment. Shipment controls unavailable.';
}
function finishShipmentLoad(message) {
panel.inert = false;
loadButton.disabled = false;
status.textContent = message;
if (previousFocus?.isConnected &&
document.activeElement === status) {
previousFocus.focus();
}
previousFocus = null;
}
These are state helpers, not a network implementation. Call beginShipmentLoad() before the request; after success or failure, update the actual shipment content and call finishShipmentLoad() with an accurate message. Keep a failure path that makes the panel usable again. If replacement content removes the previously focused control, choose a meaningful focus destination for that new content instead of trying to focus a disconnected node.
The snippet temporarily disables the load button to prevent duplicate requests. If a panel control had focus, focus moves to the status element, which is outside the inert region and has tabindex="-1" for programmatic focus. Test the actual request, replacement, and keyboard path in the application rather than assuming this helper decides every focus destination.
Choose the behavior the task needs
| Mechanism | Appropriate use |
|---|---|
inert |
A whole region and its descendants are temporarily unavailable |
disabled |
A supported form control must be unavailable, with form-specific behavior |
hidden |
The region should not be displayed |
aria-hidden="true" |
Hide information from the accessibility tree without providing an interaction lock |
aria-hidden does not stop keyboard focus or pointer interaction. CSS pointer-events: none also leaves other interaction paths, including keyboard focus. Neither is a complete substitute for making a region inert.
Inert content can remain visibly present, but users cannot select its text or find it through normal browser text search. If people need to copy the old shipment reference during the load, make a separate readable reference outside the unavailable panel or choose a narrower region to suppress.
Test the transition, including failure
Before loading, use Tab to reach Edit shipment and the record link. Start the load and verify that those controls cannot be focused or activated while the status message remains available. Confirm the visible state explains why they are unavailable.
Finish a successful request and verify that the new shipment's controls work. Repeat with a failed request, then with a response that replaces the focused control. Check where focus lands in each case and whether a screen reader receives the resulting status. These are application checks to perform; a visual opacity change proves none of them by itself.
A modal dialog opened with showModal() already makes other content inert through the platform's modal behavior. Use the native modal form pattern for that task. Applying inert manually does not create a dialog, a backdrop, an accessible dialog name, or a complete modal focus policy.
For the shipment transition, keep the final status concrete: "Shipment SH-105 loaded" or "Could not load the next shipment; SH-104 remains shown." The operator needs to know which record the restored Confirm button will act on.