HTML Snippet
HTML <dialog> and Popover API
Native modals, tooltips, and dropdowns — without a single JavaScript library.
Last updated: October 2026
Quick answer: Use <dialog> for modal dialogs. Call .showModal() to open, .close() to close. Use the popover attribute for non-modal overlays like tooltips and dropdowns. Pair with popovertarget on a button. Both features handle focus trapping, ESC key, and backdrop styling automatically.
🎬 Live Demo
Click the button to open a native modal dialog. The dropdown below demonstrates a native HTML menu.
Focus is trapped. Press ESC to close.
Open Menu ▾
<details> element. No JavaScript needed.
Same UX as popover — click summary again to close.
The <dialog> Element — Native Modals
The HTML for a modal dialog:
<dialog id="my-dialog">
<h2>Confirm Action</h2>
<p>Are you sure you want to continue?</p>
<form method="dialog">
<button>Cancel</button>
<button value="confirm">Confirm</button>
</form>
</dialog>
<button id="open">Open Dialog</button>
And the JavaScript:
const dialog = document.getElementById("my-dialog");
document.getElementById("open").addEventListener("click", () => {
dialog.showModal();
});
// A form with method="dialog" closes the dialog automatically
dialog.addEventListener("close", () => {
console.log("Dialog closed with value:", dialog.returnValue);
});
What you get for free:
- Focus trapping — Tab cycles inside the modal only.
- ESC key closes the dialog.
- Backdrop styled with
::backdrop. - Rendered in the top layer (above everything else).
- Restores focus to the trigger element when closed.
Styling the Modal
dialog {
border: none;
border-radius: 16px;
padding: 32px;
background: #1e293b;
color: #e2e8f0;
max-width: 480px;
box-shadow: 0 20px 60px rgba(0, 0, 0, 0.6);
}
/* The backdrop behind the dialog */
dialog::backdrop {
background: rgba(0, 0, 0, 0.6);
backdrop-filter: blur(4px);
}
/* Animations */
dialog[open] {
animation: slideUp 0.3s ease-out;
}
@keyframes slideUp {
from { transform: translateY(20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
The ::backdrop pseudo-element is only available on <dialog> opened with showModal(). That's the modal backdrop — no extra HTML needed.
The Popover API — Non-Modal Overlays
The popover API requires zero JavaScript. Just two attributes:
<button popovertarget="my-popover">Open Menu</button>
<div id="my-popover" popover>
<p>Popover content goes here.</p>
</div>
That's it. The browser handles opening, closing, ESC key, and click-outside dismissal. The popover renders in the top layer so it's never clipped by overflow: hidden ancestors.
You can also control it programmatically if needed:
const popover = document.getElementById("my-popover");
popover.showPopover(); // open
popover.hidePopover(); // close
popover.togglePopover(); // toggle
Popover Positioning
By default, popovers appear centered on screen. To anchor them to a trigger element, use CSS Anchor Positioning (supported in modern browsers) or manual positioning:
<button id="trigger" popovertarget="tip">Hover me</button>
<div id="tip" popover>Anchored popover</div>
<style>
#tip {
position: absolute;
top: anchor(bottom);
left: anchor(center);
translate: -50% 8px;
position-anchor: --trigger;
}
#trigger { anchor-name: --trigger; }
</style>
CSS Anchor Positioning is new but widely supported in Chrome 125+ and Safari 26+. For full cross-browser, you can fall back to a small amount of JavaScript.
Choosing Dialog vs Popover
| Use Case | Dialog | Popover |
|---|---|---|
| Confirm delete | ✅ Yes | No |
| Form in a modal | ✅ Yes | No |
| Tooltip on hover | Overkill | ✅ Yes |
| Dropdown menu | Overkill | ✅ Yes |
| Info popup with interaction behind | Blocks it | ✅ Yes |
Rule of thumb: If the user must respond before continuing, use <dialog>. If the overlay is informational or optional, use popover.
⚠️ Common Mistakes
- Using
show()instead ofshowModal().show()doesn't trap focus or render the backdrop. UseshowModal()for real modals. - Forgetting
method="dialog"on forms inside dialogs. This lets the form close the dialog automatically and setreturnValue. - Styling
::backdropon non-modal dialogs. The backdrop only exists forshowModal()dialogs, not for popovers orshow(). - Using popover for critical confirmations. Users can accidentally dismiss popovers. Use
<dialog>for actions that need a definite answer. - Assuming popover positioning. Without CSS Anchor Positioning, popovers appear centered. Set positioning manually if you need anchored tooltips.
- Not testing keyboard navigation. Always verify Tab cycles within the modal and ESC closes it.
- Overriding
dialogdisplay property. Changingdisplayon<dialog>can break the::backdrop. Only override when necessary.
❓ Frequently Asked Questions
What is the HTML <dialog> element?
The <dialog> element is a native HTML element that creates a modal dialog. It provides focus trapping, ESC key handling, backdrop styling, and top-layer rendering out of the box — replacing hundreds of lines of JavaScript.
What is the Popover API?
The Popover API lets you create non-modal overlays like tooltips, dropdowns, and menus using only HTML attributes. Set popover on an element and popovertarget on a button, and the browser handles the show/hide behavior.
What is the difference between <dialog> and popover?
<dialog> is modal — it traps focus and blocks the rest of the page until dismissed. popover is non-modal — the user can interact with the rest of the page while it's open. Use <dialog> for confirmations and forms, popover for tooltips and menus.
Is <dialog> supported in all browsers?
Yes. The <dialog> element has been supported in all modern browsers since 2022, including Chrome, Safari, Firefox, and Edge. The Popover API followed in 2023-2024.
Do I still need a JavaScript modal library?
For most use cases, no. The native <dialog> and Popover API cover confirmations, forms, tooltips, dropdowns, and menus. Libraries are still useful for complex animations or advanced accessibility requirements.