The simplest way is the native dialog element, opened with showModal(). It does the hard parts for you:
- It moves focus into the dialog.
- It makes the rest of the page inert, so users can't click or tab into it.
- It closes on Escape.
- It exposes the dialog role, so screen readers announce it as a dialog.
For a custom build, follow these steps:
- Give the container
role="dialog"andaria-modal="true". - Name it with
aria-labelledbypointing at its heading. - When it opens, move focus inside. Usually that is the first focusable control or the heading.
- Keep focus inside while it is open, for example by making the background
inert. This is called trapping focus. - Close it on Escape.
- When it closes, return focus to the element that opened it, so keyboard users don't lose their place.
All controls inside must be reachable with Tab and must work with Enter or Space. The focus indicator must stay visible.
- Prefer the native
dialogelement opened withshowModal(). - Move focus in when it opens, and return it to the trigger when it closes.
- Trap focus inside, or make the background
inert. - Escape closes it. It needs a role,
aria-modaland an accessible name.