Progressive interface foundations

Control visibility with hidden and inert

Choose hidden for irrelevant content and inert for temporarily unavailable interface regions without creating ghost controls.

Not every unavailable region should be handled the same way. hidden means the element is not relevant right now, so the browser does not render it. inert leaves a region visible but makes its descendants non-interactive and unfocusable.

On the project board, a completed-task panel can leave the current view with hidden. During an async board import, the visible board can turn inert while a status line explains what is happening. That stops edits while the underlying data is being replaced.

<section id="completed" hidden>
  <h2>Completed tasks</h2>
</section>
<main id="board">...</main>
<p id="import-status" role="status"></p>
<script>
  const board = document.querySelector('#board')
  const importStatus = document.querySelector('#import-status')
  board.inert = true
  importStatus.textContent = 'Importing project…'
  // After the import: board.inert = false
</script>

Set board.inert = true in DevTools and Tab through the page. Focus should skip the board while the status line outside it stays reachable.

Do not put aria-hidden="true" on a region that still has focusable controls. That can hide content from assistive tech while keyboard focus still lands inside it. hidden and inert change real interaction, not just an accessibility flag.

An inert region is also excluded from text selection and page find. Use it for a short, controlled unavailable state, not to dim half the page casually. Always show a clear status outside the inert region.

A modal dialog already makes the rest of the document inert when you call showModal(). Do not wrap every sibling in a home-grown inert loop when the browser is doing that job.

Try this yourself: Tab through the board, set board.inert = true, and Tab again. Toggle completed.hidden and confirm the section disappears from layout. If a visible control inside the board still receives focus, look for a browser support gap or an element rendered outside that subtree.

Lesson completed