2.1.2 No Keyboard Trap

WCAG 2.2 · 2.1.2 A Operable

What it requires

If keyboard focus can be moved to a component using the keyboard, it must be possible to move focus away from that component using the keyboard alone — using only the standard navigation keys (Tab, Shift+Tab, arrow keys, or Esc). If leaving requires more than unmodified arrow or tab keys, the user must be told the method needed to escape. In short: no part of the page may capture the keyboard and refuse to let go.

A common exception is a well-built modal dialog, which deliberately confines focus while open — that is acceptable only because Esc or a clearly reachable Close control always releases it.

This criterion protects anyone who operates the page without a mouse:

  • Keyboard-only users, including people with motor disabilities or tremors.
  • Screen reader users, who navigate entirely through the keyboard.
  • People using switch devices, sip-and-puff, or voice control that maps to keystrokes.

When focus is trapped, these users cannot reach the rest of the page and may be forced to reload or abandon the task entirely — a complete blocker, not an inconvenience.

How to detect it

Checks for keyboard traps
Check How Catches
Tab through the whole page Press Tab and Shift+Tab from top to bottom; watch the focus indicator never get stuck. Widgets, embeds, and media players that swallow Tab.
Test custom widgets Enter date pickers, menus, rich-text editors, and iframes; try to leave with Tab, arrows, and Esc. Scripted focus loops and plug-in content.
Screen reader pass Navigate with NVDA/VoiceOver to confirm reading order can move past every component. Traps that block AT navigation specifically.
Automated tools Run axe or similar. Largely not detectable automatically — traps depend on runtime focus behavior, so manual keyboard testing is essential.

How to fix it

  1. Avoid scripts that force focus to stay inside a component unless it is a modal designed to trap focus.
  2. For modals, confine focus only while open and always provide Esc plus a reachable Close button to release it.
  3. Never call preventDefault() on Tab without redirecting focus to a valid next target.
  4. Audit third-party embeds and media players; replace or wrap any that trap focus.
  5. If a component genuinely needs a non-standard exit key, announce that method in visible, programmatically associated text.
<div role="dialog" aria-modal="true" aria-label="Settings">
  <!-- focus is confined here while open -->
  <button type="button" data-close>Close</button>
</div>
<script>
  dialog.addEventListener('keydown', function (e) {
    if (e.key === 'Escape') closeDialog(); // Esc always releases the trap
  });
</script>

Copy-paste tests

Automated coverage

There is no fully automated axe-core rule for 2.1.2 — keyboard traps depend on runtime focus behavior, so this criterion needs manual review. Use the console check and steps below to surface suspects, then verify by keyboard.

Run this in the browser console

console — find-keyboard-trap-suspects.js
// Read-only: surfaces likely keyboard-trap suspects for manual review.
const suspects = [...document.querySelectorAll(
  '[role=dialog],[aria-modal=true],iframe,embed,object,[contenteditable],[tabindex]'
)].filter(el => el.tabIndex >= 0 || el.hasAttribute('aria-modal') || /iframe|embed|object/i.test(el.tagName));
suspects.forEach(el => el.style.outline = '2px solid magenta'); // visual only
console.table(suspects.map(el => ({
  tag: el.tagName.toLowerCase(),
  role: el.getAttribute('role'),
  modal: el.getAttribute('aria-modal'),
  tabindex: el.getAttribute('tabindex')
})));
console.log('%cTab/Shift+Tab and Esc through each highlighted node — can focus leave?', 'font-weight:bold');

What to check manually: Tab and Shift+Tab into every highlighted node and confirm focus can leave with unmodified Tab, arrows, or Esc — no script can confirm this. For each modal, verify Esc and a reachable Close control always release focus.