Replace your modals with <dialog> (or don't)

Tomáš KorecTomáš Korec
4 min read

The dialog element has been around for a while, and the key question is: Can it effectively replace all modal elements of various types and designs? The short answer is yes. However, there are several reasons why you should not rush to prepare for the introduction of this feature.

What is <dialog> element for?

In short, the dialog aims to alleviate the eternal problem of modal complexity (anyone who has been through it knows what I am talking about) and introduces a minimal API for opening and closing it while keeping everything simple and reliable. There is not much magic going on: by default, the modal is not visible, but this is caused by the default CSS (display: none), so you are free to override it if needed. Adding the open attribute (not a recommended way, but possible) does nothing special either, it just changes the display to block.

The real magic comes with the javascript methods that can be called on the HTMLDialogElement instance. There are two for opening the modal and one for closing it. The show() method just adds the open attribute, but the showModal() method is about something else.

showModal()

It renders the modal outside the HTML into a "top layer" while keeping the original HTML intact (the top layer element references the dialog element). The dialog element is also provided with a pseudo-element ::backdrop, which is given a basic styling. The dialog itself is centered and can be adjusted to the needs of the design. Also, the backdrop can be styled like any other element, and you could say that the backdrop-filter CSS property finally serves its purpose.

The modal can be closed using the javascript close() method on the element, or more clumsily, using the form inside the modal with action="dialog".

Pitfalls

However, there are some caveats to consider before you start replacing all your existing modals with dialogs. The good news is that it may satisfy all your needs. The problem is that for certain behaviors you may have to accept some workarounds and even give up some of the benefits that dialogs offer.

Top layer positioning

When displayed in modal mode (using the showModal() method), the dialog is displayed in a separate layer on top of any HTML elements. This prevents you from showing anything on top of the dialog. Do you have flash messages you want to show while the modal is open? They won't be visible. Do you have a custom cursor (typically created by positioning an element on the mouse position when moving)? You won't see it. Do you have an overlay effect or something that should cover the whole document? Or even a CSS filter applied to body or html? It won't apply to the dialog.

If you need one of these, the only way is to abandon the modal mode and implement it yourself with the non-modal dialog. This means creating your solution for background and positioning. The only advantage you are left with is the simple show/close API, but let's be honest, is it that much of an advantage over toggling a visible class? If you use some fading effects, you will probably have to deal with custom classes anyway.

Backdrop clicks

The second issue concerns the backdrop. Any reasonable modal that allows the user to close it should be able to be closed by clicking on the backdrop (among other possibilities, like clicking a close button or the Esc key). Although the dialog already implements closing with the Esc key, clicking on the backdrop is not easily achievable: There is no way to listen for events on pseudoelements. Of course, we can listen to the dialog itself and distinguish the dialog from its content.

modal.addEventListener('click', e => {
    if (e.target !== modal) return;

    modal.close();
});

However, this already forces us to have some element inside the dialog and also to remove a padding from the dialog element, because then clicking on the padded area would still open it. This may be a small problem, but considering how often this feature is used, it would be better to have it natively available.

On the other hand...

Rather than just mentioning problems, I would like to emphasize perhaps the biggest advantage of using dialog elements: It preserves the DOM structure as it is. So there can be an element with its modal placed inside, and this can do a great job of keeping the relationships between elements straightforward. With an ordinary modal, you either negotiate a good display from inside a deep element structure using some CSS hacking, or you place the modal at the top level in the HTML, torn away from its scope. Dialog is especially great for encapsulated or scoped components like in some javascript frameworks (Angular, React or Stimulus).

I would recommend going with the dialog element if you think all the possible drawbacks are unimportant. Even then, keep them in mind, because the result might be different from what you expected, and you don't want to refactor all your modals just to find out that some things don't work for you.

0
Subscribe to my newsletter

Read articles from Tomáš Korec directly inside your inbox. Subscribe to the newsletter, and don't miss out.

Written by

Tomáš Korec
Tomáš Korec