Everyone has experienced a cautionary moment online: placing an order, making a vote, deleting an account. These permanent actions often require an intermediary step, a prompt that ensures that the user really wants to go ahead with the process. To forestall mistakes, this prompt is usually displayed in a modal window: a UI element that usurps normal browser controls, forcing the user to make a choice (usually a binary Okay / Cancel option) before proceeding.
Traditionally, this dialog window has been created with JavaScript, most commonly via a framework or library. Today, the same modal nature is supported natively in HTML5 (more correctly, in HTML 5.1: <dialog>
didn’t quite make the official HTML5 specification). Adding one to a page is very straightforward:
Modal Markup
The basic markup for a native dialog window is what you might expect:
<dialog id="dialog">
<h3>Are you sure?</h3>
<p>You’ve pressed a big red button. It might do… something.
<div>
<button id="okay">Okay, go ahead</button>
<button id="cancel">Cancel</button>
</div>
</dialog>
By default, a browser should not show <dialog>
content until it is displayed by adding an open
attribute, using one of the methods I’m about to discuss. The action to bring up the dialog could be many things: loading the page, clicking on a big red button, or anything else. For example, to open the dialog on page load:
var dialog = document.getElementById('dialog');
dialog.show();
If you try this in a supporting browser (Chrome or Opera, as of this writing), you’ll see that the <dialog>
appears at the top of the browser window. You’ll also see that you’re still able to interact with page content (selecting text, activating other UI elements, etc). This is quite different from bringing up the <dialog>
as a modal window: change dialog.show()
to dialog.showModal()
and reload the page (alternatively, push the button at the top of this article).
While the content of the <dialog>
remains unchanged, you’ll see a few important alterations in the showModal()
API: the window now appears in the center of the viewport, and the rest of the page is dimmed and cannot be interacted with.
Controlling & Closing
In theory, a <dialog>
could contain anything that you want the user to concentrate on: a form, a video, or any other element. You can have multiple <dialog>
elements open at the same time, but only one modal dialog. For either, you will usually need a UI element that closes the window. We can use the cancel button we created earlier:
document.getElementById("cancel").onclick = function() {
dialog.close();
}
In the example for this article, both buttons close the dialog, but don’t actually do anything else. In order to make that happen, they would need to carry data, which I’ll look at in the next article.
Modal Style
<dialog>
elements can be styled using standard CSS:
dialog {
font-family: Avenir, sans-serif;
width: 25%; text-align: center; border: 3px solid;
}
dialog div {
display: flex; justify-content: space-between;
}
In addition, the showModal()
API generates a new pseudo-element, ::backdrop
, which covers the entire viewport by default and can be styled independently:
dialog::backdrop { background: rgba(0,0,0,0.9); }
In practice, modal dialogs might be considered a half-step towards the Fullscreen API: like fullscreen content, modal dialogs take over the viewport, but unlike FullScreen they don’t have to be explicitly initiated by the user. Modal dialogs can be started on pageload; fullscreen cannot.
It’s important to note that the <dialog>
window appears at the very top layer of the viewport: no amount of playing with z-index
will place anything else on top of it. As such, the position of a <dialog>
element is not inherited from any parent element. There is a proposed CSS anchor-point
property to control the alignment of <dialog>
directly, but it is not yet supported by any browser, not even via polyfill.
Support
<dialog>
doesn’t yet have great cross-browser support: it’s only supported in Chrome 37+ and Opera 24+ on desktop and mobile, although other browsers are sure to follow. In the meantime, Google has an excellent dialog polyfill that is framework-free, and works with just a few additions to your CSS.
Whether you’re using a polyfill or not, browser feature detection takes the approach of many other feature support tests: creating the element in JavaScript and testing to see if it can take an attribute value.
var testdialog=document.createElement("dialog");
testdialog.setAttribute("open", "");
if (testdialog.open==true){
// browser supports the dialog element
} else {
// browser doesn’t support the element: load a polyfill
}
As support for <dialog>
grows, it makes sense to move to using this native element over framework solutions. This is especially true given the element's strong support for form data, which I'll look at in the next article.
Enjoy this piece? I invite you to follow me at twitter.com/dudleystorey to learn more.
Check out the CodePen demo for this article at https://codepen.io/dudleystorey/pen/EaYEGw