Modal Dialogs and the Focus Trap: The Keyboard Test That Fails Most Often
Open a modal on a storefront, press Tab a few times, and watch where focus goes. On a surprising number of sites it walks straight out of the modal and into the page behind it, tabbing through the header, the product grid, and the footer while the modal sits open and unusable on top.
The four behaviors a modal must have
The WAI-ARIA Authoring Practices pattern for a modal dialog names four behaviors, and all four have to work together. Focus moves into the dialog when it opens, to the first focusable element or the dialog itself. Tab stays inside the dialog: when focus reaches the last element, the next Tab wraps to the first, and Shift Tab wraps the other way. Escape closes the dialog. And when the dialog closes, focus returns to the element that opened it. Miss any one of the four and the modal is broken for a keyboard user, even if the other three work.
The failure that shows up most in testing is the missing trap. The dialog opens, focus moves in, and then Tab walks out the bottom and into the page behind the overlay. The user is now tabbing through content they cannot see, behind a dimmed layer, with no way back except Shift Tabbing the whole way. The second most common failure is focus not returning on close: the dialog closes and focus lands on the body, so the user has to start tabbing from the top of the page. Both are component bugs, not page bugs, and they ship on every page that uses the component.
Testing it without a screen reader
You do not need a screen reader for this test. Open the modal with a mouse, then put the mouse down and use only the keyboard. Tab forward until you reach the last element in the dialog, then Tab once more: focus should wrap to the first element, not leave the dialog. Shift Tab back to the first element and keep going: focus should wrap to the last. Press Escape: the dialog should close and focus should be back on the button that opened it. Then open it again, tab through it, and confirm the same behavior holds on the second open, because dialogs that work once and break on reopen are a real pattern, usually a focus handler that only runs on mount.
Test the dialogs users actually hit, not the demo one: the size guide, the shipping info popup, the login modal, the newsletter signup, the cart drawer if it behaves like a modal. A drawer that traps focus is a modal by behavior even if the code calls it a drawer, and the same four rules apply. For the checkout version of this test, see Keyboard-Only Checkout: Time the Test, Then Fix What It Finds, and for the focus visibility side, Focus Indicator Visible: The Keyboard Test in Thirty Seconds.
The fix lives in the component
The trap belongs in the shared dialog component, not in each page that opens a dialog. The component should handle focus entry, the Tab wrap, Escape, and focus return, and every dialog on the site should inherit that behavior. When a team fixes modals one page at a time, the same bug ships again on the next page that uses a different dialog. Fix the component, test every dialog that uses it, and add a keyboard walkthrough of one dialog to the release checklist so a regression gets caught before it ships.
Frequently asked questions
What is a focus trap?
A modal dialog keeps Tab and Shift Tab inside itself. When focus reaches the last element, the next Tab wraps to the first, and Shift Tab wraps the other way. Focus never reaches the page behind the overlay while the dialog is open.
Where should focus go when a modal opens?
To the first focusable element in the dialog, or to the dialog itself if there is no better target. The screen reader should announce the dialog, not stay silent on the page behind it.
Where should focus go when a modal closes?
Back to the element that opened it. If focus lands on the body instead, the keyboard user has to start tabbing from the top of the page.
Does a cart drawer need a focus trap too?
If it behaves like a modal, yes. A drawer that blocks interaction with the page behind it is a modal by behavior, whatever the code calls it, and the same four rules apply.