← Back to Docs
Recipe

Keyboard Trap Detection & Fix

Identify and resolve focus traps that prevent keyboard users from navigating away from a component.

What is a Keyboard Trap?

A keyboard trap occurs when focus becomes locked inside a UI element — a modal, autocomplete, or rich editor — and the user cannot Tab out using standard keyboard navigation. WCAG 2.1 Success Criterion 2.1.2 requires that focus can always be moved away using the keyboard alone.

Detection Checklist

  • Tab into every interactive region on the page.
  • Attempt to Tab out — if focus loops back, a trap exists.
  • Press Escape — does focus return to a logical prior element?
  • Test with screen reader running (NVDA / VoiceOver).
  • Verify no invisible focusable elements block the path.

Fix Pattern

// 1. Trap focus only when modal is open
const trapFocus = (e: KeyboardEvent) => {
  if (e.key !== "Tab") return;
  const focusable = container.querySelectorAll(
    'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
  );
  const first = focusable[0] as HTMLElement;
  const last = focusable[focusable.length - 1] as HTMLElement;

  if (e.shiftKey && document.activeElement === first) {
    e.preventDefault();
    last.focus();
  } else if (!e.shiftKey && document.activeElement === last) {
    e.preventDefault();
    first.focus();
  }
};

// 2. Always provide an Escape hatch
const onEscape = (e: KeyboardEvent) => {
  if (e.key === "Escape") {
    closeModal();
    triggerRef.current?.focus(); // return focus
  }
};

Validation

After applying the fix, re-run the detection checklist. Confirm that Tab and Shift+Tab cycle only within the intended container while the component is active, and that Escape dismisses the component and restores focus to the triggering element.