The scenario is simple: You got a modal that looks perfect but traps keyboard users in the wrong place? Oh well, your focus management might be missing.
When a dialog opens, moving focus is not optional.
A mouse user can click inside the modal. A keyboard user needs the browser to know where they are.
Bad:
<button>Delete account</button>
<div class="modal">
Are you sure?
<button>Confirm</button>
</div>
The modal appears, but keyboard focus stays on the button behind it.
const button = document.querySelector('#confirm');
modal.show();
button.focus();
Now keyboard and screen reader users land directly where the action is.
When the modal disappears, focus should return to the element that opened it:
openButton.focus();
Otherwise users may suddenly find themselves back at the top of a page, with no idea what happened.
✅ Move focus into the dialog
✅ Keep focus inside while open
✅ Close with Escape
✅ Return focus to the trigger
The browser already knows how to handle many of these behaviours:
<dialog>
<h2>Delete account?</h2>
<button>Confirm</button>
</dialog>
Native elements give you accessibility behaviour instead of making you rebuild it yourself.
The idea is the same in React, Vue, or any other framework: keep a reference to the element that should receive focus and call .focus() when the UI state changes.
React:
const buttonRef = useRef(null);
useEffect(() => {
if (isOpen) {
buttonRef.current?.focus();
}
}, [isOpen]);
<button ref={buttonRef}>
Confirm
</button>
> Accessibility is not only about what users can see. It is also about where the browser puts them.