When to use this pattern
Use a modal dialog for short tasks that need doing now: a confirmation or a quick input. Long forms, or content people want to read alongside the page, do not belong in a dialog.
The native <dialog> element with showModal() does much of the work: the rest of the page becomes inert, Escape closes the dialog and the browser moves focus into it. Still check that focus lands back on the trigger once the dialog closes.
Roles, states and properties
- A native
<dialog>opened withshowModal(). For custom solutions:role="dialog"andaria-modal="true". - A name via
aria-labelledbypointing at the dialog heading. - Optionally
aria-describedbypointing at a short explanation. - A visible close button with an accessible name such as “Close”.
- On open, focus goes to the first sensible element; on close, back to the button that opened the dialog.
Keyboard interaction
| Key | Effect |
|---|---|
| Tab / Shift+Tab | Moves focus between elements inside the dialog; the page behind cannot be reached. |
| Escape | Closes the dialog; focus returns to the trigger. |
| Enter / Space | Activates the focused button. |
Code
<button type="button" id="open">Cancel subscription</button>
<dialog id="dlg" aria-labelledby="dlg-h">
<h2 id="dlg-h">Cancel your subscription?</h2>
<p>You can subscribe again at any time.</p>
<form method="dialog">
<button value="no">Keep it</button>
<button value="yes">Cancel subscription</button>
</form>
</dialog>
<script type="module">
const dlg = document.getElementById('dlg');
const opener = document.getElementById('open');
opener.addEventListener('click', () => dlg.showModal());
dlg.addEventListener('close', () => opener.focus());
</script>Common mistakes
- Focus stays on the page behind when the dialog opens, so keyboard users operate an invisible background.
- No way out: neither Escape nor a named close button (just an “×” with no text).
- After closing, focus jumps to the top of the page instead of back to the trigger.
- The background is only dimmed visually but still reachable by screen readers (missing
aria-modalorinert).
Related WCAG criteria
Sources
Are your components built like this?
The free check finds many issues automatically. In the audit a person tests every component with a keyboard and a screen reader.