Focus, in and out of an overlay
A modal that contains its tab sequence does not fail 2.1.2 as long as the user can leave it — the failures that actually ship are focus never entering on open, and focus never returning to the control that opened it.
Mid-run, the review gate raises a confirmation. Something needs a human answer before the agent continues, and the answer is destructive enough to be worth a dialog. It renders, it is centred, it dims the page behind it. Then someone tabs into it and the wheels come off in one of three predictable ways.
Focus never entered, so Tab keeps walking the page underneath and the first thing the user hits is a control the dialog was supposed to have blocked. Or focus entered, cannot leave, and Escape does nothing. Or the dialog closed cleanly and dropped focus back on body, so the next Tab starts from the top of the document and the user has to travel the whole page again to get back to where they were.
Exactly one of those three is a 2.1.2 failure. Knowing which is the difference between a finding that survives review and one that gets waved away.
What 2.1.2 actually forbids
2.1.2 No Keyboard Trap is Level A. The normative requirement is that where focus can be moved to a component with a keyboard, “focus can be moved away from that component using only a keyboard interface, and, if it requires more than unmodified arrow or tab keys or other standard exit methods, the user is advised of the method for moving focus away.”
Two obligations, and neither is the one people assume. Focus must be able to leave. And if leaving takes something unusual, the user has to be told what it is. That is the entire criterion.
The Understanding document then answers the modal question without being asked: “There may be times when it’s appropriate for a web page to restrict focus to a subsection of the content – for example, when the user is inside a modal dialog or popover. This does not fail the requirements of this criterion, as long as the user knows how to ‘untrap’ the focus and leave that component.”
So a modal that contains its tab sequence passes, provided the way out is known. Escape is a standard exit method and needs no special announcement. A dialog that can only be dismissed by finding a small close button somewhere in the tab order is weaker but still passes. A dialog with no keyboard exit at all fails, at Level A, and that is a finding worth writing in one line.
Where people get burned
The trap in this lesson is the reverse of the usual one. Having read the carve-out, the temptation is to swing the other way and cite 2.1.2 as the source of the whole focus contract: in on open, contained, returned on close. It says none of that. 2.1.2 forbids trapping and stops. The enter-and-return lifecycle comes from the Authoring Practices Guide, which is non-normative, and the obligations underneath it are other criteria: 2.4.3 Focus Order, Level A for a sequence that preserves meaning and operability, and 4.1.2 Name, Role, Value, Level A for the dialog reporting what it is. Cite the criterion for the obligation and the APG for the implementation, in separate sentences.
The contract the APG actually specifies
The Dialog (Modal) pattern has three moments, and shipped dialogs usually get the middle one right and both ends wrong.
On open, focus moves into the dialog
Not to the dialog’s container by default, and not left wherever it was. The pattern makes the placement a design decision with four cases worth knowing:
- For a dialog whose content is a semantic structure such as a list, table or set of paragraphs, focus a static element at the start of the content with
tabindex=“-1”, so the structure is read from the top rather than from the middle. - For long content, focus the title or first paragraph, so opening the dialog does not immediately scroll it.
- For a destructive action, consider focusing the least destructive option. A confirmation that opens with focus on Discard everything is one Enter keypress from a very bad afternoon.
- For a simple dialog, focus the most frequently used control.
The third case is the one an agentic review gate should sit with. When the interrupt is “this correction cannot be undone,” the default focus target is a decision about what a reflex keypress does.
While open, the tab sequence stays inside
Tab moves to the next tabbable element and wraps to the first when it is on the last. Shift+Tab moves back and wraps to the last when it is on the first. Escape closes. The APG’s framing of the surrounding page is the strong version: windows under a modal dialog are inert.
None of that arrives with the role. aria-modal tells assistive technology how to treat the dialog; the wrapping tab sequence is code you write, and if you write it by hand it will need testing against elements that become focusable while the dialog is open. This is the promise from the role-is-a-promise lesson, itemised.
On close, focus returns to what opened it
The pattern is specific: “Focus returns to the element that invoked the dialog unless either the invoking element no longer exists”, in which case focus moves to a logically related element, or the workflow suggests a more useful destination.
That exception is the whole reason this matters in an agentic surface. In a form, the button that opened the dialog is still sitting there when it closes. In a running agent, the step that raised the confirmation may have scrolled out of the trace, collapsed, or been replaced by its own result by the time the user answers. There is no invoking element left to return to, and the pattern anticipates exactly this: pick a logically related element and move focus there deliberately. Doing nothing is not a third option, because doing nothing sends focus to body and restarts the user’s journey from the top of the document.
Testing it in ninety seconds
Push the mouse away. Everything below is keyboard only, and the point is that it is fast enough to do on every dialog in a library rather than one showcase example.
- Tab to the control that opens the dialog. Note where you are, out loud or on paper.
- Open it. Where did focus land? If your answer is “I cannot tell,” that is a 2.4.7 Focus Visible finding before it is anything else.
- Tab all the way around, twice. Confirm you never reach anything behind the dialog and that the sequence wraps.
- Press Escape. Confirm it closes.
- Press Tab once. If the next focused element is at the top of the document, focus was dropped, whatever it looked like.
- Now repeat the whole thing with the dialog opened from a control that disappears while the dialog is open. This is the case that fails, and it is the case an agent run produces routinely.
Check your recall
Answer from memory — no scrolling back.
Retrieval check
State what 2.1.2 requires, in its own terms, and then state the three-part focus contract for a modal and where that contract comes from.
Check your answer
2.1.2 No Keyboard Trap, Level A. If focus can be moved to a component with a keyboard, it must be able to move away using only a keyboard, and if leaving needs more than unmodified arrow or tab keys or other standard exit methods, the user must be advised of the method. Restricting focus to a modal does not fail it, as long as the user knows how to leave.
The contract: focus moves into the dialog on open, the tab sequence stays inside while it is open, and focus returns to the invoking element on close unless that element no longer exists, in which case it moves to a logically related one.
Where it comes from: the APG Dialog (Modal) pattern, which is guidance and not a specification. The criteria underneath it are 2.4.3 Focus Order at Level A, 4.1.2 Name, Role, Value at Level A, and 2.1.2 for the exit. Saying “2.1.2 requires focus to return on close” is wrong and will be caught.
Hands on
Run the focus contract against the review gate’s dialog
Done when: CONFORMANCE.md has a row for each of the three focus moments — in on open, contained while open, returned on close — with a verdict, a criterion number, a remediation cost on every failure, and a separate row for the disappearing-invoker case marked unchecked if you have not tested it.
- Find every overlay in the gate: the confirmation, anything that renders in a portal, and anything that dims the page. A popover you did not think of as a dialog still has a focus contract.
- Run the ninety-second test above on each one, keyboard only. Write down where focus landed on open and where it landed after close, in words, before you form an opinion about whether that was correct.
- Check the destructive case specifically. If a confirmation opens with focus on the destructive option, record it. There is no criterion number for that one and this course is not going to attach a fake one; it is an APG recommendation and a design finding, and it should be written as exactly that.
- Force the hard case. Open a dialog from a control that the run then removes, and close it. Nine times out of ten focus goes to
body. That is a real finding and the fix is one line of code, so the remediation cost is honest and small, which makes it easy to schedule. - Write the rows. Use 2.1.2 No Keyboard Trap, Level A only where focus genuinely cannot leave. Use 2.4.3 Focus Order, Level A for the enter and return failures, and name the APG pattern in the test column as the implementation you checked against.
- Add the self-closing dialog as an
uncheckedrow with a note that no published pattern covers it. An honest empty row is a finding; a confident row nobody tested is not.
What this does not cover
Everything above was verified by watching a focus ring. That catches where focus went and tells you nothing about what was said when it got there. Whether the dialog announced itself as a dialog, whether it had an accessible name, and whether the name matched the visible title are audible facts, and the screen-reader lesson is where you learn enough NVDA and VoiceOver to hear them yourself.
The harder version of this problem is in the next module. A dialog is an interruption the user asked for by clicking something. An agent that needs an answer mid-run interrupts a user who asked for nothing, and moving focus to it is a change of context under WCAG’s own definition. The interrupting-without-hijacking lesson works through why the answer there is usually not a modal at all.
Read this next — primary source
Understanding Success Criterion 2.1.2: No Keyboard TrapW3C Web Accessibility Initiative — free, informative (non-normative companion to the normative criterion)
Short, and the shortness is the point: this criterion says far less than the people quoting it believe. Read it for the explicit carve-out that a modal dialog restricting focus does not fail, for the condition attached to that carve-out, and for the worked failure examples, which are almost all plugins and embedded objects rather than anything you wrote. Once you have read it you can tell the difference between a design that fails 2.1.2 and a design that is merely annoying, which is the difference between a Level A finding and a design opinion.
Stuck, curious, or think this lesson is wrong? Ask your teaching agent. The lessons are the scaffold; the conversation is where the learning gets unstuck.