The Native dialog Element
Build real modals with built-in focus trapping and no library.
For years, modal dialogs meant a pile of custom JavaScript to trap focus, handle the Escape key, and dim the background. The <dialog> element gives you all of that natively.
Two ways to open
dialog.show()— opens a non-modal dialog; the page behind stays interactive.dialog.showModal()— opens a true modal: focus is trapped inside, Escape closes it, and the rest of the page becomes inert behind a backdrop.
Closing it
Call dialog.close(), or — the neat trick — put a <form method="dialog"> inside. Submitting that form closes the dialog automatically and even reports which button was pressed via dialog.returnValue.
<dialog id="d">
<form method="dialog">
<button value="ok">OK</button>
</form>
</dialog>You even get a styleable backdrop for free through the ::backdrop pseudo-element.
Example
When to use it
- A confirmation dialog uses <dialog> with showModal() so the rest of the page is blocked until the user responds.
- A login form is placed inside a <dialog> that opens when the user clicks "Sign in" without navigating away.
- A delete confirmation uses <dialog> with form method="dialog" so clicking Cancel closes it and clicking Delete submits.
More examples
Modal dialog opened by button
showModal() opens the dialog as a top-layer modal with a backdrop; close() dismisses it programmatically.
<button id="open-dlg">Open dialog</button>
<dialog id="my-dialog">
<h2>Confirm action</h2>
<p>Are you sure you want to proceed?</p>
<button id="close-dlg">Cancel</button>
<button>Confirm</button>
</dialog>
<script>
const dlg = document.getElementById("my-dialog");
document.getElementById("open-dlg")
.addEventListener("click", () => dlg.showModal());
document.getElementById("close-dlg")
.addEventListener("click", () => dlg.close());
</script>Dialog with built-in form close
form method="dialog" closes the dialog on submit; returnValue holds the button value for the close handler.
<dialog id="confirm-dlg">
<p>Delete this item permanently?</p>
<form method="dialog">
<button value="cancel">Cancel</button>
<button value="delete">Delete</button>
</form>
</dialog>
<script>
const dlg = document.getElementById("confirm-dlg");
dlg.addEventListener("close", () => {
if (dlg.returnValue === "delete") {
console.log("Item deleted");
}
});
</script>Non-modal dialog as a tooltip panel
show() opens the dialog non-modally so the user can still interact with the rest of the page simultaneously.
<button id="show-info">Show info</button>
<dialog id="info-panel">
<h3>Keyboard shortcuts</h3>
<dl>
<dt>Ctrl+S</dt><dd>Save</dd>
<dt>Ctrl+Z</dt><dd>Undo</dd>
</dl>
<button id="hide-info">Close</button>
</dialog>
<script>
const panel = document.getElementById("info-panel");
document.getElementById("show-info")
.addEventListener("click", () => panel.show());
document.getElementById("hide-info")
.addEventListener("click", () => panel.close());
</script>
Discussion