Better warnings, modals, and confirmations with the <dialog> element

The World Wide Web Consortium (W3C) released HTML 5.2 as a recommendation at the end of 2017. One of the features it added to its version of the HTML5 specification is the dialog element. Think of dialog as the modal element you always wanted, and no longer have to build.

Now, it's slightly misleading to call dialog a new feature of HTML5. It's been part of the Web Hypertext Application Technology Working Group (WHATWG) version of the specification for several years now.1 Chrome added experimental support in version 32, which was released in 2014. Full support arrived a few months later. (Opera, which shares much of the same code base as Chrome, added support in version 19.)

For several years, Chrome, Opera (and other Blink/Chromium-based user agents) were the only browsers to support the dialog element. But that changed last year when Firefox added experimental support for dialog behind a flag (to enable it, change dom.dialog_element.enabled to true in about:config).

Now that the W3C has included it in its HTML 5.2 recommendation, it's a good time to learn how to use it. And yes, there's a polyfill available for browsers that lack support, although it has some limitations.

Create your first dialog

Creating a dialog is super simple.

<dialog>Hi. I am a dialog.</dialog>

You can place this anywhere in your HTML document.

Dialog elements are closed and invisible by default. To open our dialog, we'll need to add some DOM scripting. dialog has three methods — two that open the modal, and one that closes it.

  • show(): Opens the modal.
  • showModal(): Opens the modal, and makes it the top-most dialog.
  • close(): Closes the modal.

I'm sure there's a long back story replete with a flame war that explains why we have both the show() and showModal() methods. That said, there are subtle but important differences in how they operate.

  • showModal() honors the autofocus attribute, while show() may not.
  • Chrome and Opera render showModal() with a backdrop that you can style using the ::backdrop pseudo-element.2
  • dialogs opened with showModal() can be closed with the Esc key, but those opened with show() cannot (and typically don't need to be.

This is one place, by the way, where the W3C and WHATWG specifications diverge. In the W3C version of the specification, show() and showModal() accept an optional anchor point argument. In the WHATWG version, neither method accepts an argument. Since browser implementations are still emerging, that could have changed between the time I wrote and published this post and the time you began reading it.

Using the polyfill

Download the dialog-element polyfill directly from GitHub. Or use your favorite JavaScript package manager (e.g. npm install dialog-polyfill).

Link to dialog-polyfill.css from your document head. Add dialog-polyfill.js in either your document head (with the async or defer attributes) or at the end of your document body.

Once the polyfill’s CSS and JavaScript is in place, register each dialog element with the dialogPolyfill.registerDialog() method. For example:

const dialogs = document.querySelectorAll('dialog');

Array.from(dialogs).map((d) => {
  dialogPolyfill.registerDialog(d);
})

Polyfilled dialog elements work much like native ones, although the markup differs slightly. Try the demo below. Note that dialog support is incomplete and disabled by default in Firefox ≤ 59. The backdrop you'll see is markup generated by the polyfill.

I've also tweaked the user-agent styling for the dialog element in this demo. The default style is … not so aesthetically pleasing.

Determining whether a dialog is open

To test whether a dialog is open or closed, check the value of its open attribute.

const dialog = document.getElementById('newsletter_dialog');

console.log(dialog.open);

Here dialog.open returns a boolean value — true if it's open and false if it is not.

Multiple dialogs can be open at the same time. In Chrome and Opera, however, dialogs opened with showModal() will prevent interaction with elements below it in the stacking order. To guarantee that the opening of one dialog closes the others, you'll need to add some DOM scripting.

Dialogs and forms

Dialogs can contain just about any element, including forms. When used with <form method="dialog">3, we can create dialogs that are far more flexible than window.confirm().

Setting a form's method to dialog tells the browser that the form should not make a server request. Instead, submitting the form will:

  • close the dialog;
  • dispatch a close event on the dialog element; and
  • update the returnValue property of the dialog element.

We can then do something based on the value returned.

const dialog = document.querySelector('dialog');

dialog.addEventListener('close', (event) => {
  // Passes the value of the clicked button to this function
  doSomethingWithTheAnswer(event.target.returnValue);
});

Here's what this might look like in practice (view source). Note: this demo only works in Google Chrome or with the dialog polyfill. It does not work with Firefox’ implementation (as of version 59) because it is incomplete.


  1. Technically, the WHATWG's version of the specification is a Living Standard — unversioned, and updated more frequently as new element and APIs are proposed or removed. Read HTML5 is done, but two groups still wrestle over Web's future for a little more context. Although the W3C is widely viewed as the official specification, most browser vendors rely on the WHATWG specification. 

  2. Firefox supports::backdrop, but doesn't yet support ::backdrop when used with the dialog element. 

  3. Read more about <form method="dialog"> in the HTML5 specification

Subscribe to the Webinista (Not) Weekly

A mix of tech, business, culture and a smidge of humble bragging. I send it sporadically, but no more than twice per month.

View old newsletters