# A collapsed menu can still contain keyboard stops

Keep hidden navigation out of the tab order with inert, then restore focus when the menu opens and closes.

Canonical: https://calvinkennedy.com/solutions/collapsed-menu-links-still-receive-focus

## Applies to

An HTML navigation panel collapsed with CSS, with JavaScript controlling its open state. Requires browser support for the inert attribute.

## Symptom

Pressing Tab moves focus into links in a menu that appears closed. The visible page and keyboard navigation disagree.

## Cause

Collapsing the panel visually did not make its descendants non-interactive. The site header originally changed its open class and aria-expanded value without making the closed panel inert.

## Fix

Start the closed panel with inert. Remove it before focusing the first link on open. Restore it on close, update aria-expanded, and return focus to the toggle when closing with Escape. aria-hidden alone is not a substitute for removing keyboard stops.

```html
<button id="toggle" aria-expanded="false" aria-controls="menu">Menu</button>
<nav id="menu" inert aria-hidden="true">
  <a href="#content">Read the page</a>
</nav>
<main id="content" tabindex="-1">Page content</main>
<script>
  const toggle = document.querySelector('#toggle');
  const menu = document.querySelector('#menu');
  function setOpen(open, restoreFocus = false) {
    menu.inert = !open;
    menu.setAttribute('aria-hidden', String(!open));
    menu.classList.toggle('open', open);
    toggle.setAttribute('aria-expanded', String(open));
    if (open) menu.querySelector('a')?.focus();
    else if (restoreFocus) toggle.focus();
  }
  toggle.addEventListener('click', () => setOpen(menu.inert));
  menu.addEventListener('keydown', event => {
    if (event.key === 'Escape') setOpen(false, true);
  });
</script>
```

## Verify

1. Open the standalone reproduction below. In the broken example, focus its Menu button and press Tab: focus enters the visually collapsed panel.
2. In the fixed example, focus its Menu button and press Tab: focus skips the closed panel and reaches the next visible link.
3. Open the fixed menu. Its first link receives focus. Press Escape: the menu closes, aria-expanded becomes false, and focus returns to Menu. Tab again skips the closed links.

Reproduction: https://calvinkennedy.com/solutions/collapsed-menu-links-still-receive-focus/repro

## Limits

This is a disclosure navigation menu, not a modal dialog or an ARIA menu widget. It does not need a modal focus trap. A full header also needs checks for navigation, viewport changes and outside clicks. The reduced example demonstrates the closed, open and Escape paths only.

## Provenance

Source revision: d2039ad6af4fa2c3906f889d13bda7bac564b533
Source file: apps/portfolio/src/components/SiteHeader.astro
Added inert and aria-hidden to the initially closed panel, then synchronized both in the existing open and close handlers. The example is reduced from that change.
The source repository is private; the reduced public reproduction is provided for independent checks.
The public browser example checks closed-panel Tab navigation, opening and Escape focus return. It is not the complete site header.

- [MDN: inert](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Global_attributes/inert)
