DEV Community

Cover image for TIL - HTML Dialog
James Cox
James Cox

Posted on • Edited on

TIL - HTML Dialog

#TIL

Today I learned that HTML has a native modal, known as the <dialog> element.

The HTML element represents a dialog box or other interactive component, such as a dismissible alert, inspector, or subwindow.

AN HTML POP UP? NO WAY! (yes way).

As always, I demonstrate the usage in React.js, which means that some functionality translates directly, and other functionality does not. For example, according to the docs:

The ::backdrop CSS pseudo-element can be used to style behind a element when the dialog is displayed with HTMLDialogElement.showModal(). For example, to dim unreachable content behind the modal dialog.

As you will see in a moment, using a <dialog> in React requires a little bit of a different usage to dim the background. But, truthfully I think it is still easier than with vanilla JS.

The Modal

Looks great, doesn't it? And you will see in just a moment that the necessary code is relatively simple!

The Code

import { useState } from "react";
import "./styles.css";

export default function App() {
  const [isOpen, setIsOpen] = useState(false);

  const openDialog = () => {
    setIsOpen(true);
  };

  const closeDialog = () => {
    setIsOpen(false);
  };
  return (
    <div className="App">
      <h1>HTMLs Native Dialog</h1>
      <h2>A simple modal</h2>

      {isOpen && (
        <>
          <div className="overlay" />
          <dialog open>
            <p>BOOM</p>
            <p>And just like that youve got a modal</p>
            <p>
              Easy peezy lemon squeezy{" "}
              <span role="img" aria-label="lemon emojis">
                πŸ‹πŸ‹πŸ‹
              </span>
            </p>
            <button onClick={closeDialog}>Close</button>
          </dialog>
        </>
      )}
      <button className="open-btn" onClick={openDialog}>
        Open Dialog
      </button>
    </div>
  );
}
Enter fullscreen mode Exit fullscreen mode

Breaking it Down

The open or closed state of the modal is handled by the useState hook provided by React and toggled by the openDialog() and closeDialog() functions.

import { useState } from "react";

...

const [isOpen, setIsOpen] = useState(false);

const openDialog = () => {
  setIsOpen(true);
};

const closeDialog = () => {
  setIsOpen(false);
};
Enter fullscreen mode Exit fullscreen mode

The HTML for a <dialog> element looks something like:

<dialog open>
  <p>BOOM</p>
  <p>And just like that youve got a modal</p>
  <p>
    Easy peezy lemon squeezy{" "}
    <span role="img" aria-label="lemon emojis">
      πŸ‹πŸ‹πŸ‹
    </span>
  </p>
  <button onClick={closeDialog}>Close</button>
</dialog>
Enter fullscreen mode Exit fullscreen mode

The most import part of the above code is the open property in the opening <dialog> tag, written as <dialog open>. That's how the browser knows to display the modal.

And the full return statement with the conditional render handled by the isOpen property in state.

return (
    <div className="App">
      <h1>HTMLs Native Dialog</h1>
      <h2>A simple modal</h2>

      {isOpen && (
        <>
          <div className="overlay" />
          <dialog open>
            <p>BOOM</p>
            <p>And just like that youve got a modal</p>
            <p>
              Easy peezy lemon squeezy{" "}
              <span role="img" aria-label="lemon emojis">
                πŸ‹πŸ‹πŸ‹
              </span>
            </p>
            <button onClick={closeDialog}>Close</button>
          </dialog>
        </>
      )}
      <button className="open-btn" onClick={openDialog}>
        Open Dialog
      </button>
    </div>
  );
Enter fullscreen mode Exit fullscreen mode

Why Should I Care?

The cool and most important thing about the <dialog> element is better accessibility. Sure, you can build your own modal, but then you've got to work extra hard to make it available to screen readers and other accessibility tools.

Another cool benefit is not having to add a bunch of z-index properties to your CSS in order to properly display the modal and any overlays you wish to add. "Modal behaviour" is baked right into the <dialog> element.

Added accessibility AND easier styling capabilities? Sounds like a WIN-WIN to me!

The CSS

Curious how I personally styled my modal and overlay? Here is the full CSS file:

.App {
  font-family: Arial, Helvetica, sans-serif;
  text-align: center;
  color: white;
  background-color: rgb(0, 0, 0);
  min-height: 100vh;
  display: flex;
  flex-direction: column;
  align-items: center;
}

body {
  background-color: black;
}

dialog {
  margin-top: 8rem;
  width: 75%;
  color: white;
  background-color: black;
  border: 3px solid rgb(72, 70, 224);
}

button {
  background-color: rgb(72, 70, 224);
  color: white;
  border: none;
  padding: 0.5rem;
  border-radius: 0.5rem;
  cursor: pointer;
  font-size: 1rem;
  font-weight: bold;
}

button:hover {
  background-color: rgb(66, 247, 207);
  color: black;
}

.open-btn {
  width: 75%;
}

.overlay {
  position: fixed;
  margin: 0;
  top: 0;
  width: 100%;
  height: 100vh;
  background-color: rgba(9, 22, 39, 0.7);
}

@media only screen and (min-width: 500px) {
  dialog {
    width: 18rem;
  }

  .open-btn {
    width: 10rem;
  }
}
Enter fullscreen mode Exit fullscreen mode

The Overlay

The only thing I added that that doesn't come "baked in" was the overlay. I got creative with my solution, but I would not call it "difficult" or "complex". Inside my conditional render of the <dialog> element I added <div className="overlay" />. And simply styled with CSS:

.overlay {
  position: fixed;
  margin: 0;
  top: 0;
  width: 100%;
  height: 100vh;
  background-color: rgba(9, 22, 39, 0.7);
}
Enter fullscreen mode Exit fullscreen mode

Think of it as stretching a layer of slightly-transparent color across the entire screen when isOpen is true.

Conclusion

Check out this great Shopify article that features this and other useful HTML native elements. The <dialog> element is number 6 in the article and I really liked tihs part:

Does it work?
The does a slightly more complex thing…and does it well. Browser support is somewhat patchy (notably no Internet Explorer, and Safari is pending at the time of writing), but there is a polyfill.

Is it accessible?
Support is quite good, but it does need a little ARIA support to go to production. What's really good about the element is that most accessibility support is built in, making it a far better starting point than having to create your own fixed inline custom dialog component.

I hope you enjoyed my article on this awesome HTML element! As always let me know if you have any questions, comments, feedback, suggestions, etc!

Thanks again and see you next time!

Update

It appears that the <dialog> element does not behave as intended on iOS. At least not on mobile iOS. I am going to do some further digging and update this article with the relevant information as soon as possible!

Top comments (2)

Collapse
 
latz profile image
Latz • Edited

AFAIK the element is not supported by all browsers, e.g. Firefox. There's a polfill, though.

Collapse
 
jamesncox profile image
James Cox

Thanks for your comment. I hinted at this in my article this was the case in the β€œupdate” section, before I knew what the actual issue was. But yes, lack of browser support is the culprit and polyfills are the answer. I just have to learn about polyfills. I’ll make sure to update the update section to clarify. Thanks!