Dialog
A dialog component appears over the top of the main content to present information or request user input. It can be modal or non-modal:
-
Modal dialogs demand immediate attention by blocking interaction with the rest of the page. When a modal dialog is open, all content behind it becomes inert, the page cannot be scrolled, and keyboard focus is contained within it.
-
Non-modal dialogs allow people to still interact with the page content behind them.
It should always be easy and obvious how to dismiss a dialog. As well as using clear controls, we recommend adding an event listener to close the dialog using the Escape key.
Example
What problems it solves
- Modal dialogs help focus people's attention on a specific task or decision, minimising distractions and reducing the risk of unintended actions, such as accidental deletions or submissions
- Non-modal dialogs allow focused attention while still being able to see or interact with the rest of the page content as needed
When to use it
- Modal dialog: When you need to interrupt the user flow to ask for input or confirmation, or to deliver important information that requires people's attention before they continue, for example confirming a delete action
- Non-modal dialog: For supplementary content, secondary features, or when people still need to be able to access background content, for example a web chat
When not to use it
Do not use dialogs for:
- Messages that will unnecessarily disrupt people, or obscure important context
- Frequent, low-priority notifications
- Multi-step processes
Where to use it
Modal dialogs visually open in the centre of the viewport, on top of everything else.
Place a modal dialog in the HTML as a direct child of the <body> element, as a modal dialog has to make the rest of the page inert, and it can only do that cleanly when nothing else is wrapped around it. Nested inside another element, it remains part of that element's landmark in the accessibility tree, and could become hidden or inert by inheriting from its ancestors. Any fallback script that makes the dialog's siblings inert would also leave the rest of the page interactive.
Non-modal dialogs visually sit in the bottom right corner of the viewport, where they are least likely to cover the content people are working with. However, if a non-modal dialog obscures the element that has keyboard focus, it temporarily moves out of the way.
Place a non-modal dialog in the HTML wherever it is most logical, ideally close to the control that opens it. Because the browser renders an open dialog on top of other elements, it's easy for it to feel detached, so its position in the markup is important to provide context for screen reader users.
How it works
The component is built using a native <dialog> element. Each control points at its dialog with the commandfor attribute and says what it does with the command attribute: show-modal opens a modal dialog, --show opens a non-modal one, and close closes either. A modal dialog makes the rest of the page inert and dims it, and also carries aria-modal="true". A non-modal dialog leaves the page interactive.
When a dialog opens, focus moves to the dialog itself, so that its name and content are announced together. When it closes, focus returns to the control that opened it, regardless of how it was dismissed. The Escape key also closes either dialog.
Inside a modal dialog, Tab wraps from the last control back to the first. The browser would otherwise let focus leave the dialog and enter the browser toolbar, which can be confusing while the page behind is inert.
A non-modal dialog sits over the page, but the page is still active. This means it can hide the focus indicator on elements behind it. When that happens the dialog temporarily moves out of the way, and moves back once focus has moved on.
Without JavaScript
The modal variant works without the script in browsers that support invoker commands, which are Chrome and Edge 135, Firefox 144 and Safari 26.2 or later. The browser opens the dialog from its trigger, closes it from its buttons or the Escape key, moves focus into it, and makes the page behind it inert. In older browsers the trigger does nothing and the dialog stays closed.
The non-modal variant has no native command to open it, so it is open in the markup by default with its controls hidden. Without the script, it renders as a block of content where it is placed in the DOM, which is why its position in the markup is important. When the script runs, it closes it, moves it to the corner of the viewport, and reveals the controls that open and close it, so modal content is never missing.
The script adds the following enhancements.
- Focus moves to the dialog when it opens
- Focus is returned to the trigger when it closes
- Keyboard focus is contained inside a modal dialog and does not escape to the browser controls
- Escape closes the non-modal dialog
- The non-modal dialog temporarily moves when obscuring a focused element behind it
Assistive technology compatibility
This component has been tested with the following browsers and assistive technologies.
| Assistive technology | Result | Notes |
|---|---|---|
| Keyboard | No issues | No notes |
| Voice Access/Chrome 154.0.8/Windows 11 | No issues | No notes |
| JAWS 2026.2603.86/Chrome 154.0.8/Windows 11 | No issues | No notes |
| NVDA 2026.1.1/Firefox 157.0/Windows 11 | No issues | No notes |
| VoiceOver/Safari macOS Tahoe 26.6 | No issues | No notes |
| VoiceOver/Safari/iOS 26.0 | No issues | No notes |
| TalkBack/Chrome 154.0.8/Android 17 | No issues | No notes |
| Windows Contrast themes | No issues | No notes |
| Windows Magnifier and/or Apple Zoom | No issues | No notes |
| Browser zoom | No issues | No notes |
| prefers-reduced-motion | Not applicable | There are no animations to reduce |
Last updated: 13 October 2026.