Artboard 16light, inspiration, solution, idea, innovation,Google Sheets iconSwift icon
Published at
Updated at
Reading time
6min

A long time ago in 2014, the dialog element landed in Chromium 37. The idea behind the HTML element was to make it easier to build modals, dialogs and popups.

The specification defines the element as follows:

The dialog element represents a part of an application that a user interacts with to perform a task, for example a dialog box, inspector, or window.

We have 2022 now and almost made it to use the dialog element! ๐ŸŽ‰ In March, starting with Safari 15.4 (Safari release notes) and Firefox 98 (Firefox release notes), both missing browsers ship the element that's been included in Chromium for ages.

This progress brings us to a cross-browser-supported dialog element in all evergreen browsers soon!

MDN Compat Data (source)
Browser support info for Dialog element
chromechrome_androidedgefirefoxfirefox_androidsafarisafari_iossamsunginternet_androidwebview_android
373779989815.415.43.037

Firefox and Safari shipping the element is excellent for accessibility because building an accessible modal has always been complicated. Read Scott O'Hara's article "Having an open dialog" to learn more about modal accessibility.

I played with this new way to build dialogs and discovered that the HTMLDialogElement not only differentiates between non-modal and modal dialogs but also comes with modal functionality that's hard to get right.

Let's have a look at the dialog's super powers!

The basics of the dialog element

To get started, drop the element into your pages and find out that ...

Playground
Preview

... you won't see anything. The supporting browsers include the following CSS in their user-agent styles.

dialog:not([open]) {
  display: none;
}

The dialog element is hidden by default, and its visibility relies on a present open attribute. Let's add it to the HTML!

Playground
Preview

And here we have it โ€“ a visible dialog element!

Usually, you would open dialogs via JavaScript, but if you server-render pages after a form submit, defining it in HTML might make sense to show a modal after the page has loaded.

You could now tinker with the open attribute via JavaScript to show the dialog, but hold on! The element provides two additional methods for dynamic interactions.

show() โ€“ an absolute positioned dialog with proper focus handling

To show a dialog as a non-modal, access the dialog element from the DOM and call its show method.

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

// to close the dialog use `close`
dialog.close();

See it in action below.

Playground

dialog.show() opens an absolute position non-modal dialog.

Hello world from the dialog

Even though this functionality looks like a simple element display toggle, more things are going on. ๐ŸŽ‰

The show method adds the open attribute to the dialog element, the element is absolute positioned following the user-agent styles, and the closing button is automatically focused.

You don't see mouse-triggered focus states on my site, because it uses :focus-visible. If you want to see the focus outlines, focus and press the "Open dialog" button with your keyboard.

CSS from Chrome, Edge and Safari showing that the dialog element is absolute positioned.

But browsers are not only moving the focus into the modal when you open it. The focus will be moved back to the previously focused element if you close the modal with dialog.close(), too. That's pretty handy and very valuable for accessibility and keyboard usability.

These features are valuable to build non-modal popups, but what about the traditional full-page-covering modals? How do you create the modal page overlay, and how could you prevent users from clicking buttons or links outside the open dialog?

showModal provides all these functionalities!

showModal() โ€“ a fixed positioned dialog with some super powers

To create a modal dialog covering all the other page content, use the showModal method.

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

// to close the dialog use `close`
dialog.close();

See it in action by clicking the button below.

Playground

dialog.showModal() opens a fixed positioned modal dialog, it's closeable by pressing ESC and all other elements become inaccessible.

Hello world from the dialog

The showModal method differs in multiple ways from show.

The modal dialog is position: fixed

If you inspect the modal, you'll see that Safari and Chromiums provide the styling via dialog:-internal-modal or dialog:-internal-modal-dialog.

CSS in Chrome, Edge and Safari showing that a modal opened with `showModal` comes with a special '-internal-modal-dialog' pseudo class.

The dialog element is now fixed positioned and covers whatever was rendered on the screen.

The modal dialog provides a ::backdrop pseudo-element

Additionally, the dialog element comes with a ::backdrop overlay pseudo element when it's opened via showModal.

/* Included in the Chrome user agent styles */
dialog::backdrop {
  position: fixed;
  top: 0px;
  right: 0px;
  bottom: 0px;
  left: 0px;
  background: rgba(0, 0, 0, 0.1);
}

Unfortunately, neither Chromium nor Safari show the ::backdrop pseudo-element in the elements panel yet.

How to close the modal on ::backdrop click

The number one missing thing I see people pointing out is that the dialog doesn't automatically close when clicking the backdrop. I'd argue that it would have been valuable to put this functionality into the spec, but I'm sure there's a good reason not to.

Luckily you can work around that by adding a click handler to the dialog element and using the bubbly nature of click events.

dialog.addEventListener('click', (event) => {
  if (event.target.nodeName === 'DIALOG') {
    dialog.close();
  }
});

Click events bubble up the DOM tree. If there's a button inside a div inside the html element, you can attach a click handler to the html element and react to button clicks.

Adam shared that you can leverage this event behavior and close the dialog when someone clicks the backdrop overlay. If someone clicks on elements inside the dialog element such as buttons or a form, event.target.nodeName will be the particular node name (BUTTON or FORM). But if someone clicks the overlay, it'll be DIALOG because the pseudo-element belongs to the dialog.

See the nifty little trick in action below.

Playground

dialog.showModal() opens a fixed positioned modal dialog, it's closeable by pressing ESC and all other elements become inaccessible.

Hello world from the dialog

But there's more fancy stuff!

The modal dialog can be closed via ESC

There's nothing more to say other than there's no need to add keypress event handlers all over the place. ๐ŸŽ‰ Also, if the dialog is closed by pressing ESC, a cancel event is triggered.

The modal dialog makes everything else inaccessible

If you open a modal dialog, you can't click other elements anymore and that's not only because the backdrop covers them. If you hit the TAB key, you'll also find that all the other interactive elements are inaccessible.

It's only the open dialog element you can interact with!

The inert element theoretically provides ways to make elements inaccessible, but there doesn't seem to be any browser movement to implement this attribute anytime soon.

dialog โ€“ a welcome addition to the web platform

I love seeing more typical UI use cases entering the web platform. And the dialog element is more than welcome because building accessible modals is much more than toggling the display CSS property. The more functionality browsers provide, the better for everyone.

The dialog element is also included in the Interop 2022 initiative, in which browser vendors work together to make building for the web easier for developers.

It's refreshing to see all the browser movement lately. I can't wait to see what's next!

Further reading

Here are more resources if you want to learn more about the dialog element.

Related Topics

Related Articles