WCAG Success Criteria · Level A
WCAG 2.1.2: No Keyboard Trap
WCAG 2.1.2 requires that keyboard users are never trapped inside a component — if focus can be moved into a UI element using a keyboard, it must also be possible to move focus away using only the keyboard. This criterion is essential for users who rely exclusively on keyboard navigation, including people with motor disabilities and screen reader users.
- Level A
- Wcag
- Wcag 2 2 a
- Operable
- Accessibility
What This Rule Means
WCAG 2.1.2 — No Keyboard Trap — is a Level A success criterion under the Operable principle. It states: "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, and, if it requires more than unmodified arrow keys or tab keys to move focus away, the user is informed of the method for moving focus."
In practical terms, this means that every interactive component on a webpage that a keyboard user can tab into must also allow the user to tab out of it. A keyboard trap occurs when a user navigates into a widget, dialog, custom form control, embedded media player, or any other focusable region and is then unable to leave using standard keyboard controls — they are, in effect, stuck.
The criterion covers all HTML elements that can receive keyboard focus: native interactive elements such as <input>, <select>, <textarea>, <button>, and <a> tags, as well as custom widgets that receive focus via tabindex, ARIA roles, or JavaScript focus management. It applies equally to embedded third-party components such as chat widgets, video players, map embeds, date pickers, and rich text editors.
A component passes this criterion if a keyboard user can always move focus away from it using standard keys — typically Tab, Shift+Tab, Escape, or arrow keys — or if the page clearly informs users of a non-standard keyboard mechanism to move focus away. A component fails if focus becomes locked inside it with no keyboard-accessible exit path, or if the only exit mechanism requires a mouse click, touch gesture, or other non-keyboard input.
WCAG does provide a narrow exception: it is acceptable to constrain keyboard focus within a component temporarily when doing so is part of a deliberate and accessible design pattern — most notably, a modal dialog. A modal dialog should trap focus within the dialog while it is open (to prevent users from interacting with obscured background content), but it must always provide a keyboard-accessible means to close the dialog and release focus — such as an Escape key handler or a clearly labeled close button reachable by Tab. This kind of intentional, escapable focus containment is not a keyboard trap; it is a correct implementation of the modal dialog pattern. The trap only becomes a failure when the user cannot escape at all.
Why It Matters
Keyboard traps are one of the most severe accessibility failures a website can have. Unlike many other accessibility issues that degrade the experience for certain users, a keyboard trap can completely block a user from continuing to use a page. It is essentially the equivalent of placing a physical barrier in a hallway and providing no way around it.
The groups most severely affected are users with motor or physical disabilities who cannot operate a mouse and rely entirely on keyboard navigation. This includes people with conditions such as repetitive strain injury, multiple sclerosis, Parkinson's disease, quadriplegia, and cerebral palsy. According to the World Health Organization, approximately 1.3 billion people — 16% of the global population — live with some form of significant disability, and motor impairments represent a substantial portion of that figure. For these users, encountering a keyboard trap on a checkout page, a login form, or a customer service chat widget can mean they are entirely unable to complete the task.
Screen reader users — primarily blind and low-vision users — are also heavily affected. Screen readers such as NVDA, JAWS, and VoiceOver navigate entirely via keyboard commands. If focus becomes trapped in a component, the screen reader user hears the same element repeated as they press Tab, with no way to proceed forward or backward through the page. This is deeply disorienting and forces the user to close the browser tab or refresh the page, losing any progress they had made.
Consider this real-world scenario: a user with limited hand mobility visits a Turkish e-commerce site to purchase a product. They add an item to their cart and proceed to checkout. The checkout page includes a third-party address autocomplete widget built with a custom JavaScript framework. The widget opens a dropdown suggestion list when the address field receives focus. The developer forgot to add keyboard event handling to close this dropdown — so once the user tabs into the address field and the dropdown appears, they cannot Tab out, cannot press Escape, and cannot close the dropdown without a mouse click. The user is completely blocked from completing the purchase. This is not a minor inconvenience — it is a total exclusion from the service.
Beyond disability access, keyboard traps also affect power users who prefer keyboard navigation for speed, users in enterprise environments where mouse use is restricted, and users on certain mobile or hybrid devices with hardware keyboards. Fixing keyboard traps therefore improves the experience for a broader audience than just users with disabilities.
Related Axe-core Rules
WCAG 2.1.2 requires manual testing. No automated axe-core rule directly and reliably detects keyboard traps. This is because automated tools operate by analyzing the static structure of the DOM — they can identify focusable elements, check tab order, and validate ARIA attributes, but they cannot simulate the full interactive keyboard navigation experience that a human tester performs. A keyboard trap typically emerges from JavaScript event handling logic that intercepts or suppresses keyboard events at runtime; this behavior is not visible in the DOM structure and cannot be inferred by a static analyzer.
- Manual testing required — no dedicated axe-core rule: Axe-core does not ship a rule that automatically detects keyboard traps because the failure mode is fundamentally behavioral. The trap only manifests when a user actually navigates into a component with the Tab key and attempts to leave. An automated scanner cannot replicate this because it would need to simulate sequential keyboard navigation across every focusable element on the page, trigger all associated JavaScript event listeners, and then determine whether focus has escaped the intended region — a problem that is computationally intractable for complex pages. Additionally, what constitutes a trap versus intentional focus containment (such as a modal) requires contextual judgment that automated rules cannot reliably make. Testers should use axe DevTools or Lighthouse to identify focusable elements and tab order issues as a starting point, but must then manually keyboard-navigate through every interactive region to confirm no traps exist.
How to Test
- Run an automated accessibility scan as a baseline. Open axe DevTools (browser extension) or run a Lighthouse accessibility audit in Chrome DevTools. While neither tool will flag a keyboard trap directly, the scan will identify focusable elements, missing ARIA roles, and incorrect tab order that may indicate risky interactive components worth investigating manually. Note any custom widgets, embedded iframes, third-party components, modal dialogs, dropdown menus, date pickers, carousels, and rich text editors — these are the most common sources of keyboard traps.
- Disconnect or set aside your mouse. For manual keyboard testing to be valid, you must not use a mouse. Place your mouse out of reach or disable it in your operating system settings to avoid accidentally relying on it during testing.
- Navigate the entire page using only the Tab and Shift+Tab keys. Starting from the browser address bar or the top of the page, press Tab repeatedly and observe where focus moves. Visually track the focus indicator at each step. When you reach each interactive component — especially any custom widget, embedded content, or complex UI element — verify that pressing Tab or Shift+Tab moves focus cleanly out of the component to the next or previous focusable element on the page.
- Test each interactive component individually. For modal dialogs: open the modal, verify focus moves inside it, then press Escape and confirm focus returns to the triggering element. For dropdown menus: open the dropdown, navigate within it, then press Escape and confirm the dropdown closes and focus returns to the trigger. For date pickers, color pickers, and similar widgets: tab in, interact, then tab out and confirm focus exits. For embedded iframes (e.g., maps, video players, chat widgets): tab into the iframe, navigate within it, and confirm you can tab out of it back to the main page.
- Test with NVDA and Firefox. Open NVDA, navigate to the page in Firefox, and use Tab to move through interactive elements. Pay attention to whether NVDA reads a new element each time you press Tab or whether it appears to loop back to the same element. If Tab does not advance focus past a component, this is a keyboard trap.
- Test with VoiceOver and Safari on macOS. Enable VoiceOver (Command + F5), open the page in Safari, and use the Tab key to navigate. Confirm that VoiceOver announces a new element at each Tab press and that focus is never stuck in a region you cannot exit.
- Test with JAWS and Chrome. Open JAWS, navigate the page in Chrome, and use Tab to navigate through all interactive components. Specifically test any component that uses JavaScript-driven focus management, as JAWS interacts with the accessibility tree in ways that can reveal traps not visible with visual testing alone.
- Check for non-standard escape mechanisms. If any component requires a key other than Tab, Shift+Tab, or Escape to exit, verify that the page clearly communicates this to the user — for example, via on-screen instructions, a tooltip, or an ARIA live region announcement when focus enters the component.
How to Fix
Modal Dialog Without Escape Handling — Incorrect
<!-- Modal opens but has no Escape key handler and no close button reachable by keyboard -->
<div id='modal' role='dialog' aria-modal='true' aria-labelledby='modal-title'>
<h2 id='modal-title'>Confirm Your Order</h2>
<p>Are you sure you want to place this order?</p>
<button onclick='submitOrder()'>Confirm</button>
<!-- No close button, no Escape key listener -- keyboard users are trapped -->
</div>
Modal Dialog Without Escape Handling — Correct
<!-- Modal with proper focus trap, Escape handler, and accessible close button -->
<div id='modal' role='dialog' aria-modal='true' aria-labelledby='modal-title'>
<h2 id='modal-title'>Confirm Your Order</h2>
<p>Are you sure you want to place this order?</p>
<button onclick='submitOrder()'>Confirm</button>
<!-- Close button is reachable by Tab and allows keyboard users to exit -->
<button id='modal-close' onclick='closeModal()' aria-label='Close dialog'>Cancel</button>
</div>
<script>
document.addEventListener('keydown', function(e) {
if (e.key === 'Escape') {
closeModal(); // Escape key closes the modal and returns focus to trigger
}
});
function closeModal() {
document.getElementById('modal').hidden = true;
document.getElementById('modal-trigger').focus(); // Return focus to opener
}
</script>
Custom Dropdown Capturing All Tab Key Events — Incorrect
<!-- Custom dropdown intercepts all keydown events including Tab, preventing focus from leaving -->
<div id='custom-select' tabindex='0' role='combobox' aria-expanded='true'>
<ul role='listbox'>
<li role='option' tabindex='-1'>Option 1</li>
<li role='option' tabindex='-1'>Option 2</li>
<li role='option' tabindex='-1'>Option 3</li>
</ul>
</div>
<script>
// BUG: This captures ALL keyboard events and calls preventDefault on Tab,
// meaning the user can never Tab out of this component
document.getElementById('custom-select').addEventListener('keydown', function(e) {
e.preventDefault(); // This traps the keyboard
if (e.key === 'ArrowDown') { /* move focus down */ }
if (e.key === 'ArrowUp') { /* move focus up */ }
});
</script>
Custom Dropdown Capturing All Tab Key Events — Correct
<!-- Correct: Only prevent default for arrow keys used for internal navigation;
allow Tab and Escape to function normally so users can exit -->
<div id='custom-select' tabindex='0' role='combobox' aria-expanded='false'>
<ul role='listbox' hidden>
<li role='option' tabindex='-1'>Option 1</li>
<li role='option' tabindex='-1'>Option 2</li>
<li role='option' tabindex='-1'>Option 3</li>
</ul>
</div>
<script>
document.getElementById('custom-select').addEventListener('keydown', function(e) {
if (e.key === 'ArrowDown' || e.key === 'ArrowUp') {
e.preventDefault(); // Only prevent default for internal navigation keys
// move focus between options
}
if (e.key === 'Escape' || e.key === 'Tab') {
// Do NOT call preventDefault -- allow Tab and Escape to propagate
// so the browser can move focus away from this component naturally
closeDropdown();
}
});
</script>
Embedded Third-Party Iframe With No Exit Path — Incorrect
<!-- An embedded chat widget iframe that absorbs all Tab keypresses
and never returns focus to the parent page -->
<iframe
src='https://example-chat-widget.com/embed'
title='Customer support chat'
width='350'
height='500'>
</iframe>
<!-- The iframe's internal JavaScript consumes Tab events, trapping users inside it -->
Embedded Third-Party Iframe With No Exit Path — Correct
<!-- Use a button to open the chat in a new window rather than embedding
an iframe that may trap keyboard users -->
<button
id='open-chat'
onclick='window.open("https://example-chat-widget.com", "_blank", "noopener")'>
Open Customer Support Chat (opens in new window)
</button>
<!-- If an iframe must be used, add a visible skip link before it
so keyboard users can bypass it if they choose -->
<a href='#after-chat-widget' class='skip-link'>Skip chat widget</a>
<iframe
src='https://example-chat-widget.com/embed'
title='Customer support chat'
width='350'
height='500'>
</iframe>
<span id='after-chat-widget' tabindex='-1'></span>
Common Mistakes
- Calling
event.preventDefault()inside akeydownlistener without scoping it to specific keys — applyingpreventDefault()to all keyboard events on a focusable component blocks Tab and Shift+Tab from functioning, instantly creating a keyboard trap. Always scopepreventDefault()to only the specific keys your component needs to handle internally (such as Arrow keys for listboxes). - Building a modal dialog that sets focus inside it but provides no Escape key handler or close button — developers often implement the focus-entry part of the modal pattern correctly but forget that focus containment inside a modal is only acceptable if there is always a keyboard-accessible exit. Every modal must handle the Escape key and include a tabbable close button.
- Using
tabindex='-1'on a container element to prevent it from appearing in the tab order, while still allowing JavaScript to programmatically move focus into it — when focus is moved into atabindex='-1'element viaelement.focus(), there is no natural Tab target to leave it by, which can strand the user if no further keyboard handling is implemented. - Embedding third-party widgets (chat, maps, video) without auditing them for keyboard trap behavior — vendors do not always build their embedded widgets to be keyboard-accessible. Site owners remain responsible for all content on their pages, including third-party embeds. Always test embedded components manually and, if they trap keyboard users, wrap them with a skip link or replace them with a keyboard-safe alternative.
- Implementing a focus trap for a modal or drawer but not releasing the trap when the component closes — if the JavaScript that constrains focus is not properly cleaned up when the modal closes, it can continue to intercept Tab events and trap the user on the now-invisible layer.
- Using CSS
visibility: hiddenordisplay: noneto hide the close button of a dialog for visual design reasons without providing an alternative keyboard exit — if the close button is visually hidden but not removed from the accessibility tree, screen reader users can still find it; but if it is hidden from the accessibility tree as well, there may be no exit. Confirm all close mechanisms are keyboard-operable even if visually styled to be discreet. - Building custom autocomplete or type-ahead components that open a suggestion list and then route all Tab keypresses to cycling through suggestions rather than exiting — users should be able to press Escape to close the suggestion list and then Tab to move to the next form field. Autocomplete widgets that redirect Tab to internal navigation violate this criterion.
- Forgetting to test rich text editors (WYSIWYG editors such as TinyMCE, CKEditor, or Quill) — these components manage their own keyboard interaction internally and are a frequent source of keyboard traps. Always confirm that pressing Escape or a documented key sequence exits the editor and returns focus to the page's normal tab order.
- Assuming that because a component uses native HTML elements it cannot be a keyboard trap — a
<select>element inside a form that uses JavaScript to override its blur event can still trap focus. The use of semantic HTML does not guarantee keyboard-trap-free behavior when custom JavaScript event handling is layered on top. - Not providing on-screen documentation when a non-standard key is required to exit a component — WCAG 2.1.2 explicitly allows components that require non-standard keys to exit, provided the user is informed. If your widget requires pressing F6 or a custom key combination to leave, you must clearly communicate this to the user, ideally via visible instructions adjacent to the component or an ARIA live region announcement when focus enters.
Relation to Turkey's Accessibility Regulations
Turkey's Presidential Circular 2025/10, published in the Official Gazette No. 32933 on June 21, 2025, establishes binding digital accessibility requirements for a wide range of public and private sector entities operating in Turkey. The circular mandates conformance with internationally recognized web accessibility standards — aligning with WCAG 2.1 Level AA as the baseline, which encompasses all Level A criteria including WCAG 2.1.2 No Keyboard Trap.
WCAG 2.1.2 is a Level A criterion, which represents the minimum level of conformance. Under the circular, Level A conformance is mandatory for all covered entities. Public institutions are required to achieve this conformance within one year of the circular's publication, while private sector entities are given two years to comply.
The entities covered by the circular are broad and include public institutions and government bodies at all levels, e-commerce platforms and online marketplace operators, banks and financial services institutions, hospitals and healthcare providers, telecommunications companies with 200,000 or more subscribers, travel agencies, private transport companies, and private schools authorized by the Ministry of National Education (MoNE). This means that a failure to address keyboard traps on a website or web application operated by any of these entities constitutes a direct breach of Turkey's mandatory accessibility regulations.
Given the prevalence of keyboard trap failures in complex web applications — particularly in online banking portals, hospital appointment booking systems, e-commerce checkout flows, and telecom account management pages — WCAG 2.1.2 deserves particular attention in the Turkish compliance context. These are exactly the types of interaction-heavy, JavaScript-driven interfaces most likely to contain custom widgets, modal dialogs, and third-party embeds that can inadvertently trap keyboard users.
Organizations subject to the circular should treat keyboard trap testing as a non-negotiable part of their accessibility audit process. Because automated tools cannot reliably detect keyboard traps, covered entities must invest in manual keyboard testing conducted by qualified accessibility specialists, ideally including users with disabilities, as part of their path to compliance. Failure to remediate keyboard traps identified during audit represents not only a legal risk under the circular but also a significant barrier to access for users with motor and visual disabilities who depend on keyboard navigation to use digital services.
