Skip to content
exercises
Accessibility

Keyboard-first menu

Arrow keys, type-ahead, escape, tab — by the spec.

IntermediateSelf

Build a dropdown menu that meets the ARIA Authoring Practices Guide (APG) for menubutton: arrow key navigation, Home/End, type-ahead, Escape, and correct focus management.

The ARIA Pattern

A compliant menu has:

  • Button with aria-haspopup="menu" and aria-expanded
  • Menu with role="menu" and aria-labelledby pointing to the button
  • Items with role="menuitem" and tabindex="-1" (focus managed by JS)

Only the button receives Tab focus. Arrow keys move focus within the menu. Escape closes and returns focus to the button.

Key Handlers

function handleMenuKeyDown(e) {
const items = [...menu.querySelectorAll('[role="menuitem"]')];
const current = items.indexOf(document.activeElement);
switch (e.key) {
case "ArrowDown":
e.preventDefault();
items[(current + 1) % items.length].focus();
break;
case "ArrowUp":
e.preventDefault();
items[(current - 1 + items.length) % items.length].focus();
break;
case "Home":
e.preventDefault();
items[0].focus();
break;
case "End":
e.preventDefault();
items[items.length - 1].focus();
break;
case "Escape":
closeMenu();
button.focus();
break;
}
}

Type-Ahead

Type-ahead lets users jump to an item by pressing its first letter:

let typeAheadTimer;
let typeAheadString = "";
function handleTypeAhead(key) {
clearTimeout(typeAheadTimer);
typeAheadString += key.toLowerCase();
typeAheadTimer = setTimeout(() => {
typeAheadString = "";
}, 500);
const match = items.find((item) =>
item.textContent.trim().toLowerCase().startsWith(typeAheadString),
);
match?.focus();
}

Opening Direction

The menu should open toward available space. Check viewport bounds before deciding:

const rect = button.getBoundingClientRect();
const spaceBelow = window.innerHeight - rect.bottom;
menu.classList.toggle("opens-up", spaceBelow < menu.offsetHeight);

Why It Matters

Keyboard navigation is the primary interface for many users — motor impairments, power users, screen reader users. A menu that only works with a mouse is broken for a significant portion of your audience.