2.1.2 No Keyboard Trap
If keyboard focus can be moved to a component of the page using a keyboard interface, then focus can be moved away from that component using only a keyboard interface.
What this rule means
WCAG 2.1.2 requires that when a keyboard user tabs or navigates into any component on a page, they must be able to move focus away from that component using standard keyboard mechanisms. Focus must never become trapped in a way that the user cannot escape without using a mouse or other pointing device.
If a component does require non-standard keyboard behavior to exit (such as pressing Escape to close a modal), the user must be informed of the method. The key principle is that no keyboard user should ever become stuck in a component with no way to leave.
Why it matters
A keyboard trap is one of the most severe accessibility barriers. When a user becomes stuck in a component, they lose the ability to interact with the rest of the page entirely. They cannot navigate to other content, submit forms, or even close the browser tab using keyboard commands. The only escape is to close and reopen the browser — losing all page state and unsaved work.
This is especially dangerous for users who rely exclusively on keyboard input. Blind users, users with motor impairments using switch devices, and voice input users all depend on predictable focus movement. A keyboard trap turns a minor navigation issue into a complete dead end.
Related axe-core rules
There are no automated axe-core rules that directly test for keyboard traps. Detecting focus traps requires manual testing because automated tools cannot fully simulate the sequential keyboard interaction needed to identify when focus cannot leave a component.
How to test
Manual keyboard testing is the most reliable way to detect keyboard traps.
- Tab through every interactive element on the page using only the Tab and Shift+Tab keys.
- When focus enters a custom component (modal, widget, embedded content), attempt to Tab out of it.
- If Tab alone does not move focus out, try Escape, arrow keys, and other standard keyboard shortcuts.
- Test embedded content: iframes, third-party widgets, embedded media players, and WYSIWYG editors are common trap sources.
- Verify that modal dialogs allow focus to be released when closed via Escape or a close button.
- Pay special attention to custom date pickers, autocomplete fields, rich text editors, and embedded maps.
How to fix
Ensure every component provides a keyboard mechanism to move focus out. Intentional focus trapping (modals) must include an escape route.
Modal dialog with proper focus management
<!-- Modal that traps focus intentionally but provides escape -->
<div role="dialog" aria-modal="true"
aria-labelledby="modal-title" id="modal">
<h2 id="modal-title">Confirm Action</h2>
<p>Are you süre you want to proceed?</p>
<button onclick="confirm()">Yes</button>
<button onclick="closeModal()">Cancel</button>
</div>
<script>
const modal = document.getElementById('modal');
const focusableEls = modal.querySelectorAll(
'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
);
const firstEl = focusableEls[0];
const lastEl = focusableEls[focusableEls.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Escape') {
closeModal();
return;
}
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === firstEl) {
e.preventDefault();
lastEl.focus();
} else if (!e.shiftKey && document.activeElement === lastEl) {
e.preventDefault();
firstEl.focus();
}
}
});
</script>
Preventing accidental traps in custom widgets
// Bad: keydown handler prevents all default behavior
widget.addEventListener('keydown', (e) => {
e.preventDefault(); // This traps focus!
handleWidgetKey(e);
});
// Good: only prevent default for handled keys
widget.addEventListener('keydown', (e) => {
if (['ArrowUp', 'ArrowDown', 'Enter', ' '].includes(e.key)) {
e.preventDefault();
handleWidgetKey(e);
}
// Tab and other keys pass through naturally
});
Embedded content escape
<!-- Provide instructions for non-standard exit -->
<p class="sr-only">
Press Escape to exit the embedded editör and return
to the main page.
</p>
<div id="editör" tabindex="0"
aria-label="Rich text editör. Press Escape to exit.">
<!-- Editor content -->
</div>
Common mistakes
- Calling e.preventDefault() on all keydown events inside a widget, preventing Tab from moving focus out.
- Modal dialogs that do not close when Escape is pressed, trapping keyboard users inside.
- Third-party embedded widgets (chat, maps, video players) that capture all keyboard input.
- Infinite focus loops in custom components where Tab cycles endlessly among child elements with no exit.
- JavaScript-based focus management that forcibly returns focus to a component after the user tabs away.
- Missing instructions when non-standard keys (like Escape) are required to exit a component.
Resources
- Deque University: Keyboard Traps— Deque University
- W3C WAI: ARIA Dialog Pattern— W3C WAI