A modal opens while focus stays behind it
The dialog is visible, but keyboard navigation still follows the obscured page.
The problem
The dialog is on screen, but the keyboard is still on the page behind it.
What happens Tab walks the page behind the dialog. Read moreRead less
Activate Edit details. A dialog covers the page. Press Tab: focus moves through navigation links behind the overlay instead of entering the dialog.
Why it fails It looks modal. Nothing makes it behave so. Read moreRead less
The visual layer changed without establishing a modal interaction. The user can reach hidden background actions and may not encounter the dialog heading.
Who is affected Keyboard and screen-reader users, in the wrong context. Read moreRead less
A keyboard or screen-reader user may continue editing the wrong context, miss required input, or lose their place after closing.
What automation and AI miss role and aria-modal do not move focus. Read moreRead less
Correct role and aria-modal attributes do not move focus or prevent background interaction. A static DOM snapshot cannot prove opening, containment, dismissal, and restoration across the actual workflow.
Try it
Open the dialog, then press Tab.
Open the dialog, then press Tab and Escape.
A recreated demo. The broken version is intentionally inaccessible.
The fix
Open a native dialog with showModal(), and check where focus goes on close.
- 1Give the dialog a name with
aria-labelledby. - 2Put initial focus where the task starts, or on the least destructive action.
- 3Return focus to the trigger, or to a sensible place if it is gone.
html
<div class="overlay" hidden> <div class="modal"> <p class="modal-title">Edit details</p> <button onclick="closeModal()">Close</button> </div></div>js
function openModal() { document.querySelector('.overlay').hidden = false;}html
<button type="button" id="edit-trigger">Edit details</button> <dialog id="edit-dialog" aria-labelledby="edit-title"> <h2 id="edit-title">Edit details</h2> <form method="dialog"> <label for="display-name">Display name</label> <input id="display-name" name="name"> <button value="save">Save</button> <button value="cancel">Cancel</button> </form></dialog>js
const trigger = document.getElementById('edit-trigger');const dialog = document.getElementById('edit-dialog');trigger.addEventListener('click', () => dialog.showModal());js
// If the trigger no longer exists after closing, choose where focus goes.dialog.addEventListener('close', () => { if (!trigger.isConnected) document.getElementById('item-list')?.focus();});Why this works
Showing the overlay changes what people see, nothing else. Focus stays on the trigger, Tab continues through the page behind, Escape does nothing, and the dialog has no name.
showModal() moves focus into the dialog, makes the page behind it inert, and closes the dialog on Escape. Buttons in a method="dialog" form close it too. Current browsers return focus to the element that opened it; still verify this, because a re-rendered page may have replaced that element.
Implementation decisions
A long dialog may need initial focus on a heading with tabindex="-1" so its beginning stays visible. Destructive confirmations should put initial focus on the least destructive action; use autofocus on that button. Avoid nesting dialogs until their restoration behavior is tested.
If you cannot use the native element, a custom modal needs the same behavior: role="dialog" with aria-modal="true" and a name, focus moved in on open, the rest of the page made inert, Escape to close, and focus returned on close.
Verify the fix
5 checks, no mouse.
Record the OS, browser and assistive-technology versions, the build, the date, and the actual result of each step. Repeat after the shared dialog component changes.
Limits
This is a starting pattern, not a guarantee for every application. The snippets omit saving and validation. Test the complete journey with your target assistive technology.
This is a recreated teaching example, not a finding about a named client. The code is a starting pattern: test it in your own product. No completed assistive-technology test is claimed here.
References: www.w3.org
Keep this fixed as your code changes.
Turn guides like this into rules your coding agents and CI follow, then have the result retested with a keyboard and screen readers.