The dialog element
Simplify pop-ups and modals using the HTML dialog element.
Updates
The native dialog element has known accessibility issues that likely won't be resolved in the near future. I recommend considering the latest iteration of a11y-dialog as an alternative to the suggestions provided in this article.
Let's talk about pop-ups. And modals, overlays, or anything else you like to call them (remember Lightbox?). Despite user experience concerns, these elements remain popular on the web. But technical implementations can be wildly inconsistent. Looking to stop reinventing the wheel? This post will help guide you in your quest to show content on top of other content.
Problem
Implementing solutions for pop-ups can be difficult. What seems trivial on the surface can become more complicated in a hurry. You may need to account for modal and popover designs. And animations. How about custom behavior on form submissions? What happens if there is more than one modal trying to display at the same time?
To help with that, you may reach for a plugin solution. But there are so many choices, and a lot of topics to consider:
- API
- Accessibility
- Dependencies. You might not want jQuery, React, or similar.
- Support. Who is maintaining it? How soon are issues addressed?
- Extensibility. How easy is it for me to customize and add new features?
Of course you may choose to build your own instead. But how flexible is it? Can you reuse as-is in other places? What about other projects?
Solution
Enter the HTML dialog element! Published in HTML 5.2 (2018), <dialog>
is a native browser element for creating pop-ups and modals.
<dialog open>
<h1>Hello</h1>
</dialog>
A dialog element provides:
- An element that is easy to show and hide, including an
open
boolean attribute on the element itself. - Two versions: a standard popover or modal version.
- A ::backdrop pseudo-element for modal types.
- Built-in focus: see dialog focusing steps.
- ARIA role support (
dialog
is the implied default). Also accepts the alertdialog role. - A pending stack for multiple dialogs.
- A DOM interface with the
open
boolean and methodsshow
,showModal
, andclose
.
And those are just some highlights! Showing content on top of other content has never been easier.
Standard Use
<dialog id="dialog">
<h1>Hello</h1>
</dialog>
<script>
var dialog = document.getElementById('dialog');
dialog.show();
</script>
Modal Use
The modal version is activated by method, i.e. dialog.showModal()
. This differs from standard use in a couple of ways:
- Guaranteed to be on top of any other elements regardless of their z-index.
dialog::backdrop
provided for styling.- Close with Esc key.
<dialog id="dialog">
<h1>Hello</h1>
</dialog>
<script>
var dialog = document.getElementById('dialog');
dialog.showModal(); // "showModal" instead of "show"
</script>
::backdrop
Target dialog::backdrop
to style the background of a modal dialog. Really handy for a semi-transparent background overlay.
dialog::backdrop {
background-color: rgba(0, 0, 0, 0.8);
}
Dialog Forms
A new form attribute, method="dialog"
, can be used within dialog elements. Specifying the attribute provides the contents of the submit button's value
attribute to the dialog element itself.
<dialog id="dialog">
<form method="dialog">
<p>Would you like to continue?</p>
<button type="submit" value="no">No</button>
<button type="submit" value="yes">Yes</button>
</form>
</dialog>
<script>
var dialog = document.getElementById('dialog');
dialog.showModal();
dialog.addEventListener('close', function (event) {
if (dialog.returnValue === 'yes') { /* ... */ }
});
</script>
Caniuse?
At the time of this writing, browser support for the dialog element is about 70% globally. But there is hope for more. Firefox's implementation is behind a flag. Edge status for the dialog is under consideration, stating "...likely for a future release." You can cast votes supporting development on Edge.
Polyfill
Now you need a polyfill. Audible sigh. That being said, I believe it's worthwhile to continue with dialog, even in this intermediate state. If you're with me, here are two options to consider right now.
Google Chrome Polyfill
Pros: drop-in polyfill from the Google Chrome team. Easy to use. Cons: not super small.
https://github.com/GoogleChrome/dialog-polyfill
a11y-dialog
Pros: very small. Built with accessibility in mind. React and Vue variants available. Cons: requires more markup than a drop-in polyfill.
https://github.com/edenspiekermann/a11y-dialog