2.1.2 No Keyboard Trap
Level: A | Principle: Operable | Since: WCAG 2.0 | Automation: Manual
What This Means
If keyboard focus can be moved to a component on the page, focus must also be movable away from that component using only the keyboard. If it requires more than standard navigation keys (Tab, Shift+Tab, Arrow keys, Escape), the user must be informed of the method to move focus away.
A keyboard trap makes the page completely unusable for keyboard-only users — they get stuck and cannot reach the rest of the content.
Who This Affects
- Keyboard-only users — become completely stuck, unable to navigate past the trap
- Screen reader users — cannot escape the trapped region to access other content
- Switch device users — rely on sequential navigation and have no way to break free from a trap
Common Pitfalls
1. Modal dialogs that trap focus without an exit
<!-- Bad: focus enters the modal but there is no way to close it via keyboard -->
<div class="modal" tabindex="-1">
<p>You are trapped here forever.</p>
</div>
2. Embedded content (iframes) that capture focus
<!-- Bad: third-party widget captures focus with no escape -->
<iframe src="https://third-party-widget.com/chat"></iframe>
3. Custom widgets with event.preventDefault on Tab
// Bad: prevents Tab from moving focus out
input.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
e.preventDefault();
// custom autocomplete logic
}
});
How to Fix
Modal with proper focus management
<!-- Good: modal with close button and Escape key support -->
<div class="modal" role="dialog" aria-modal="true" aria-label="Confirm action">
<p>Are you sure you want to proceed?</p>
<button onclick="closeModal()">Cancel</button>
<button onclick="confirm()">Confirm</button>
</div>
// Good: Escape closes the modal and returns focus
document.addEventListener('keydown', (e) => {
if (e.key === 'Escape' && modalIsOpen) {
closeModal();
triggerButton.focus(); // return focus to the element that opened the modal
}
});
Focus cycling within modals (not trapping)
// Good: cycle focus within modal, but allow Escape to exit
function trapFocusInModal(modal) {
const focusable = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
const first = focusable[0];
const last = focusable[focusable.length - 1];
modal.addEventListener('keydown', (e) => {
if (e.key === 'Tab') {
if (e.shiftKey && document.activeElement === first) {
e.preventDefault();
last.focus();
} else if (!e.shiftKey && document.activeElement === last) {
e.preventDefault();
first.focus();
}
}
});
}
How to Test
- Starting from the top of the page, press Tab through every interactive element, paying special attention to modals, iframes, media players, rich text editors, and autocomplete fields.
- At each element, verify you can press Tab or Shift+Tab to move away from it.
- When a modal or dialog opens, confirm you can close it with Escape and that focus returns to the element that triggered it.
- Test embedded third-party widgets (chat, video players, maps) to ensure Tab moves focus out of them.
- Pass: Focus can be moved away from every element using standard keyboard navigation (Tab, Shift+Tab, Escape).
- Fail: Focus gets stuck on any element with no keyboard method to escape, or a modal traps focus with no close mechanism.
axe-core Rules
No automated axe-core rules. This criterion requires manual testing.