A modal fails keyboard users in three specific ways, and each has a matching fix: focus is never moved into the dialog when it opens, focus is allowed to wander out behind it while it is open, or there is no reliable way to close it. The remedy is a single discipline applied in order: move focus in, contain it while the modal is open, restore it to where it came from on close, and always support dismissal. A modal is not just a styled overlay; it is a piece of state that has to manage focus deliberately, and an unmanaged one strands the very users who depend on the keyboard.
The first failure is the quiet one. A designer triggers the modal, the overlay paints, the backdrop dims, and to a mouse user everything looks correct. But focus is still sitting on the button that opened it, somewhere behind the dim layer. A keyboard user has no idea the dialog exists in any actionable sense, and a screen reader keeps reading the now-inert page underneath. The fix is to move focus into the modal the moment it opens, landing it on a sensible element such as the first input, the close button, or the dialog container itself, and to mark the dialog with role="dialog" and aria-modal="true" plus an accessible name so assistive tech announces it as a dialog.
The second failure is leakage. Even when focus starts inside, pressing Tab past the last focusable element will, by default, send focus to the browser chrome or to the content behind the modal, where the user can interact with a page they cannot see properly and then has no path back. This is the actual “trap” worth building: a focus loop that keeps Tab and Shift+Tab cycling among the modal’s own focusable elements while it is open, wrapping from last to first and first to last. The background should also be inert (using the inert attribute or equivalent) so nothing behind the overlay is reachable by keyboard or screen reader at all.
A concrete example: a checkout page opens a “Confirm your address” modal with two fields and Save and Cancel buttons. Done wrong, the user tabs into the first field, through Save, past Cancel, and then straight out into the page’s main navigation menu behind the overlay, with no visible focus ring and no way to find their way back to Cancel except by reverse-tabbing through the entire site. Done right, Tab from Cancel wraps back to the first field, Shift+Tab from the first field wraps to Cancel, Escape closes the dialog, and on close focus returns to the “Edit address” link that opened it so the user resumes exactly where they left off.
The one limit to respect is the difference between a deliberate trap and an accidental one. A modal dialog should contain focus while open, but it must always offer an exit: an Escape key handler, a clearly focusable close button, and (for non-destructive dialogs) often a click on the backdrop. A focus loop with no way out is not accessibility, it is a cage. The narrow exception is a genuinely blocking flow, such as a critical confirmation, where backdrop-dismiss may be intentionally disabled, but even then Escape or an explicit Cancel must remain.
When you build a modal, wire up the full sequence: store the element that triggered it, move focus inside on open, loop Tab within the dialog while making the rest of the page inert, support Escape and a visible close control, and return focus to the trigger on close. Then close your mouse drawer and operate the whole thing by keyboard alone; if you can get stuck, get lost, or get out by accident, the focus management is not done.