Dialog
A modal with entry/exit animations, backdrop blur, light dismiss, focus trapping and Esc-to-close. Zero JavaScript — the button opens it declaratively.
dialogexit animations
How it works
- Native
<dialog>gives you the top layer, focus trapping, inert background and Esc-to-close for free. commandfor+command="show-modal"on the trigger opens it declaratively. This invoker commands API replaces thedialog.showModal()call you’d otherwise write in JavaScript.closedby="any"adds light dismiss: clicking the backdrop closes it. If a stray click must not dismiss it (destructive confirms), use the Alert Dialog instead.- Entry animation:
starting:open:*(that’s@starting-style) defines where the dialog animates from. Exit animation: the base classes are the closed state, andtransition-discrete(transition-behavior: allow-discrete) keepsdisplayalive until the transition finishes. - The backdrop animates the same way via
backdrop:, including abackdrop-blur. - The one thing native modals don’t give you is a scroll lock: the page behind is inert but
still scrolls.
overscroll-noneon the dialog plusbackdrop:overflow-hidden backdrop:overscroll-containon the backdrop keep the scroll from chaining out —nonerather thancontainso the dialog’s own scroll doesn’t rubber-band at its edges either. Needs Chrome 144+ (whereoverscroll-behaviorstarts applying to non-scrollable containers); everywhere else the background scrolls, nothing breaks. - Tailwind v4’s preflight zeroes all margins, which removes the browser’s built-in dialog
centering.
m-autoputs it back so keep it.
Accessibility
Everything the JS dialog libraries reimplement (focus trap, aria-modal, inert page behind,
focus restore on close) is the browser’s native behavior here. The one thing <dialog> does
not supply is an accessible name: point aria-labelledby at the title (and aria-describedby
at the body text) like the demo does, so screen readers announce what the dialog is asking.
Browser support
Minimum stable version per engine, resolved at build time from MDN's browser-compat-data; Baseline status from the official web-features dataset. Everything degrades gracefully — the “when missing” column is the actual behavior, not a broken page.
| Feature | Chrome | Edge | Firefox | Safari | When missing |
|---|---|---|---|---|---|
| <dialog> elementBaseline · widely available | 37 | 79 | 98 | 15.4 | Baseline, widely available. Modal behavior, focus handling and Esc-to-close are native. |
| Invoker commands (commandfor / command)‡Baseline 2025 · newly available | 135 | 135 | 144 | 26.2 | Buttons with commandfor do nothing. Until Baseline reaches your audience, open the dialog with a 3-line shim or from your framework. |
| closedby="any" (light dismiss)‡Limited availability | 134 | 134 | 141 | ✕ | Esc still closes the dialog (platform default); clicking the backdrop does not. |
| Entry/exit animations (allow-discrete + @starting-style)†Baseline 2024 · newly available | 117 | 117 | 129 | 17.5 | Elements appear and disappear instantly. Nothing breaks — you just lose the animation. |
† @supports cannot test at-rules, so the badge checks transition-behavior: allow-discrete, which co-shipped with @starting-style in every engine.
‡ HTML feature — @supports can only test CSS, and we ship no JS to detect it, so it gets no live badge.