WCAG 2.1.2 · Level A · EN 301 549 9.2.1.2

No Keyboard Trap

Requires that when focus can move into a component with the keyboard, it can also move out again with the keyboard.

In brief

A keyboard user can tab into a component and then not get out again. They cannot go back and they cannot go forward. The only way out is a mouse, which they do not have, or reloading the page and losing their work.

This criterion requires that if keyboard focus can be moved to a component using a keyboard interface, then focus can also be moved away from it using only a keyboard interface. If this needs more than the arrow keys, Tab or other standard exit methods, the user must be told how.

What does it cover?

  • The rule: Wherever focus can go, focus can leave, using only the keyboard.
  • Typical traps: Embedded players, rich text editors, third-party widgets, iframes, maps and plug-ins.
  • Modal dialogs: Keeping focus inside an open modal dialog is not a trap, provided Escape or a visible close button lets users leave it.
  • Non-standard exits: If a component needs an unusual key to leave, the user must be told, before or on entering.
  • Whole page: It applies to all content on the page, including content from other sources.
  • Out of scope: Operability of controls is 2.1.1. Moving focus unexpectedly on its own is 3.2.1.

Who does it affect?

Keyboard-only users and screen reader users who get stuck and must leave. People who use a switch or voice control. They may lose their work or be unable to continue.

In the EAA and EN 301 549

The European Accessibility Act (Directive (EU) 2019/882) applies to in-scope products and services placed on the market after 28 June 2025. Recital 47 names four principles for websites and mobile applications: perceivable, operable, understandable and robust. A way out of every component is part of "operable".

The technical counterpart is the standard EN 301 549, which incorporates WCAG 2.1.2 by reference and turns it into separate clauses for each kind of ICT.

Where WCAG 2.1.2 appears in EN 301 549
ClauseType of ICTWhat it requires
9.2.1.2Web pagesWeb content must satisfy WCAG success criterion 2.1.2.
10.2.1.2Non-web documents (PDF, Office files)Documents must not trap keyboard focus where the standard applies the criterion to them.
11.2.1.2Non-web software (native mobile apps)Software must not trap keyboard focus.

Whether and how the criterion applies to non-web documents is stated in clause 10 of the standard. Clause numbers follow the "9. + WCAG number" pattern of EN 301 549. In V3.2.1 the software clause is divided into further subclauses for open and closed functionality. Check the exact numbers in the standard when you cite them.

Standard version: EN 301 549 V4.1.1 (September 2026) is based on WCAG 2.2 and is the first version prepared specifically for the EAA. It has not yet been cited in the Official Journal of the European Union, so for now it is best treated as a voluntary technical route to the EAA's requirements. Once cited, it will give a presumption of conformity. The text of criterion 2.1.2 is the same in WCAG 2.1 and 2.2.

A note on EAA scope: Article 2(4) of the Directive excludes certain content from the requirements, for example office file formats published before 28 June 2025 and archives that are not updated after that date. Content you publish or change after that date is not covered by these exclusions.

Directive (EU) 2019/882, EUR-Lex, opens in a new tab

Code examples for the web

1. A widget that swallows Tab

Preventing the default Tab behavior with no exit leaves the user stuck.

Incorrect
editor.addEventListener("keydown", e => {
  if (e.key === "Tab") e.preventDefault(); // inserts a tab, no way out
});
Correct
editor.addEventListener("keydown", e => {
  if (e.key === "Escape") { editor.dataset.trap = "off"; } // Esc, then Tab leaves
  if (e.key === "Tab" && editor.dataset.trap !== "off") {
    e.preventDefault(); insertTab();
  }
});
// Document it: "Press Escape, then Tab, to leave the editor."

2. A modal dialog that can be closed

A native dialog keeps focus inside while it is open and closes with Escape.

Incorrect
<div class="modal">…</div> <!-- focus wraps and no close key -->
Correct
<dialog id="settings" aria-labelledby="t">
  <h2 id="t">Settings</h2>
  …
  <button type="button" onclick="this.closest('dialog').close()">Close</button>
</dialog>
<script>settings.showModal(); // Escape closes it</script>

3. Embedded content

Third-party players and widgets can trap focus. Test them and pick ones that do not.

Incorrect
<iframe src="https://widget.example/chat" title="Chat"></iframe> <!-- traps Tab -->
Correct
<iframe src="https://widget.example/chat" title="Chat"></iframe>
<!-- After testing: Tab enters and leaves; if not, change or replace the widget -->

4. A focus loop with no exit

A script that returns focus to the first element on every Tab loops for ever.

Incorrect
last.addEventListener("keydown", e => {
  if (e.key === "Tab" && !e.shiftKey) { e.preventDefault(); first.focus(); }
});
Correct
// Loop only inside an open modal dialog that has a close button and responds to Escape

5. A panel that opens over the page

When a non-modal panel opens, let users continue with Tab out of it and close it with Escape.

Incorrect
panel.addEventListener("focusout", () => panel.querySelector("input").focus());
Correct
panel.addEventListener("keydown", e => {
  if (e.key === "Escape") { panel.hidden = true; trigger.focus(); }
});

6. Background content while a dialog is open

Make the page behind a modal inert so focus stays where it should.

Incorrect
<main>…</main> <!-- still tabbable behind the dialog -->
Correct
<main inert>…</main> <!-- while the dialog is open -->

Code examples for mobile

Native apps can trap focus in custom views and overlays. Make sure every overlay can be dismissed with a keyboard or switch.

iOS (SwiftUI)

import SwiftUI

struct SettingsSheet: View {
    @Environment(\.dismiss) private var dismiss

    var body: some View {
        NavigationStack {
            Form { /* controls */ }
                .navigationTitle("Settings")
                .toolbar {
                    // A visible close control that works with keyboard and VoiceOver
                    ToolbarItem(placement: .confirmationAction) {
                        Button("Done") { dismiss() }
                    }
                }
        }
        // Standard sheets also dismiss with Escape on a hardware keyboard
    }
}

Android (Jetpack Compose)

import androidx.compose.material3.*
import androidx.compose.runtime.Composable

@Composable
fun SettingsDialog(onDismiss: () -> Unit) {
    // AlertDialog closes with Back/Escape and keeps focus inside while open
    AlertDialog(
        onDismissRequest = onDismiss,
        title = { Text("Settings") },
        text = { /* controls */ },
        confirmButton = {
            TextButton(onClick = onDismiss) { Text("Done") }
        }
    )
}

How to test

  • Tab through the entire page: Move forward and backward through every control. Can you always keep going?
  • Enter each widget: Tab into editors, players, maps, embedded content and menus. Can you leave using the keyboard?
  • Try Escape and Tab: Does Escape close overlays? Does Tab move out of widgets? If a special key is needed, is it explained?
  • Test dialogs: Does focus stay inside an open modal dialog, and can you close it with Escape or a visible button?
  • Test third-party content: Chat widgets, cookie banners, ads and video players are common culprits.
  • Check mobile: With a hardware keyboard or a switch, can you leave every sheet and overlay?
  • Use a checker as a starting point: Automated tools cannot detect traps. A person must tab through each component.

Common mistakes

  • Swallowing the Tab key in an editor: The classic trap.
  • Modal dialogs without a close key: Escape and a visible close button must both work.
  • Third-party widgets that capture focus: Test them before adding them.
  • Unlimited focus loops: A loop is only acceptable inside a dismissible modal.
  • Cookie and promo banners with no exit: They must be dismissible by keyboard.
  • Unexplained exit keys: If a special key is needed, tell users.
  • Focus moved back on blur: Pulling focus back prevents users from leaving.
  • Only testing with a mouse: Traps are invisible to mouse users.

Sources

Standard version: EN 301 549 V4.1.1 (2026-09), WCAG 2.2. This page is for informational purposes only and is not legal advice. For binding requirements, refer to the official texts of the European Accessibility Act (Directive (EU) 2019/882) and EN 301 549.

Corpowid is recognized by Gartner

Corpowid has been recognized by Gartner, a leading global research and advisory firm, for our innovation and performance in digital accessibility. These badges reflect our commitment to creating inclusive, AI-powered web experiences.

Have questions about Corpowid?

Let’s connect.

We will get back to you as soon as possible.