HTML Dialog Tag : Creating modals has never been easier
The HTML dialog element gives you native modals: showModal(), ::backdrop, Escape to close, focus handling and forms. Examples, styling and support.
Every front-end codebase used to carry a modal implementation: a fixed overlay, a focus trap, an Escape handler, a scroll lock, and a bug list for each of them. The HTML <dialog> element does all of it natively, and since September 2024 it is Baseline widely available, so there is no longer a reason to ship your own.
The minimum
<button id="open">Delete account</button>
<dialog id="confirm" aria-labelledby="confirm-title">
<h2 id="confirm-title">Delete your account?</h2>
<p>This cannot be undone.</p>
<form method="dialog">
<button value="cancel">Cancel</button>
<button value="delete" autofocus>Delete</button>
</form>
</dialog>
<script>
const dialog = document.getElementById("confirm");
document.getElementById("open").onclick = () => dialog.showModal();
dialog.addEventListener("close", () => {
if (dialog.returnValue === "delete") deleteAccount();
});
</script>Three things happen for free here. showModal() puts the dialog on the top layer, above every z-index, and makes the rest of the document inert. Focus moves into the dialog, to the autofocus element, and cannot tab out. Escape closes it. And the form with method="dialog" closes the dialog on submit and stores the pressed button's value in returnValue, so the result is read in one place.
Modal or not
show() opens the same element without the modal behaviour: no backdrop, no inert page, no focus trap. Use it for non-blocking panels such as a cookie notice or a "saved" toast that should not stop the user. Use showModal() for anything that needs an answer before the user continues.
Styling
dialog {
width: min(90vw, 28rem);
border: 0;
border-radius: 14px;
padding: 1.5rem;
box-shadow: 0 20px 60px rgba(0, 0, 0, .3);
}
dialog::backdrop {
background: rgba(10, 15, 34, .55);
backdrop-filter: blur(2px);
}
dialog[open] {
animation: pop .18s ease-out;
}
@keyframes pop {
from { transform: scale(.96); opacity: 0; }
}The dialog is centred by the user-agent stylesheet, so no positioning is needed. ::backdrop is only rendered for modal dialogs. For a closing animation, newer browsers let you transition display with @starting-style and transition-behavior: allow-discrete; older ones simply close instantly, which is an acceptable fallback.
Light dismiss
Closing on a click outside used to need a click handler that checked the event target. The closedby attribute now does it declaratively: <dialog closedby="any"> closes on outside click as well as Escape, closedby="none" disables even Escape for dialogs that must be answered. It is newer than the element itself, so keep the JavaScript fallback until your browser matrix allows dropping it:
dialog.addEventListener("click", (e) => {
if (e.target === dialog) dialog.close("cancel"); // click landed on the backdrop area
});Accessibility checklist
- Give the dialog a name with
aria-labelledbypointing at its heading, so screen readers announce what opened. - Put
autofocuson the control the user most likely wants, or on the first field of a form; never leave focus on the close button of a destructive confirmation. - Do not use
<dialog open>in markup for modals; it opens non-modally. CallshowModal()from script. - Restore the user's place: the browser returns focus to the opening button when the dialog closes, which is one more thing you no longer write.
Browser support
Chrome 37 was first, in 2014; Firefox 98 and Safari 15.4 completed the set in March 2022, which made it Baseline newly available, and it reached widely available on 14 September 2024. Any site that still bundles a modal library for the basic case is carrying weight it does not need.
Reference: dialog on MDN and its Web Platform Status entry.
Frequently asked questions
hat is the difference between show() and showModal()?
show() opens a non-modal dialog that sits in the page flow; the rest of the page stays interactive. showModal() opens it on the top layer, makes everything else inert, traps focus inside, closes on Escape and renders the ::backdrop.
Is the dialog element supported everywhere?
Yes. It is Baseline widely available since September 2024: Chrome 37, Edge 79, Firefox 98 and Safari 15.4.
How do I close a dialog from a form without JavaScript?
Put a form inside the dialog with method="dialog". Submitting it closes the dialog and sets dialog.returnValue to the value of the button that was pressed.