Using <dialog> and :modal

With a new :modal CSS pseudo-class landing in Chrome 105, we now have a full support in 4 major browsers including Chrome, Edge, Firefox and Safari.

What is it about?

:modal is a special (just like any other) pseudo-class, that is used to target elements that prevent user interactions with the rest of the page. This, for example, could be a Dialog opened with a showModal() method, or an element that is selected by the :fullscreen pseudo-class when opened with the requestFullscreen API.

We will jump directly into an example, where we will see how to utilize it, and why was it created anyway. Thanks to Jhey Tompkins for pointing out its existence.

Step 1. Throwing together the HTML page.

Let’s throw together a simple HTML page with a <dialog> element, and a couple buttons to trigger it:

    <div class="warning-message">
      :modal isn't supported in this browser :(
    </div>

    <dialog>
      <p>I'm a Dialog</p>
      <button>Close</button>
    </dialog>

    <h1><code>&lt;dialog&gt;</code> and <code>:modal</code> example</h1>
    
    <div class="actions">
      <button data-modal="true">Open Modal</button>
      <button data-modal="false">Open Non-modal</button>
    </div>

Here each element does its small part. warning-message is for browsers that don’t support :modal, <dialog> element is the actual dialog with the Close button, then goes the simple page title and 2 buttons to open the Dialog in 2 different modes. Some JavaScript is required to open the dialog box:

const buttons = document.querySelectorAll("button");
const dialog = document.querySelector("dialog");

buttons.forEach((button) => {
  button.addEventListener("click", (e) => {
    let modalStyle;
    switch (button.getAttribute("data-modal")) {
      case "true":
        modalStyle = "showModal";
        break;
      case "false":
        modalStyle = "show";
        break;
      default:
        modalStyle = "close";
    }
    dialog[modalStyle]();
  });
});

When clicking on any button on a page, we check if there is a data-modal attribute, and all either a show() or showModal() method, otherwise the button is probably meant to close() the dialog.

Now if you try to open the non-modal version of the dialog, it will appear without any auxiliary styling around the modal (because we called the non-modal version). However, we now have the ability to target both modal and non-modal versions with a pseudo-class.

Step 2. The actual CSS.

  dialog[open]:not(:modal) {
    z-index: 2;
    transform-style: preserve-3d;
  }

  dialog[open]:not(:modal):before {
    content: "";
    position: fixed;
    height: 100vh;
    width: 100vw;
    top: 50%;
    left: 50%;
    background: hsl(180 100% 40% / 0.25);
    transform: translate3d(-50%, -50%, -1px);
  }

This will effectively add a slightly faded backdrop to the dialog when it was opened in a non-modal mode. Here is the Codepen with all the additional CSS required for the demo.

Live Demo.

Additional resources:


Did you know that I made an in-browser image converter, where you can convert your images without uploading them anywhere? Try it out and let me know what you think. It's free.

Leave a Comment

Your email address will not be published. Required fields are marked *