How to use <dialog> in React — Easy Modals & Tooltips

Marek Bombera
5 min readAug 2, 2023

--

ReatDOM.createPortal vs <dialog>

Modals in React have always been a pain. You need to use ReactDOM.createPortal, manage a state, render the modal conditionally, make sure users can’t select any other element on the page (not just with a mouse but shift+tabas well) etc. etc.

All of a sudden creating simple modal has become a complex mess.

The answer to this problem is a native HTML <dialog> element.

First of all, I’d like to look at the <dialog> element from a regular HTML and Javascript point of view. If React is all you care about, don’t hesitate to jump right to the React and <dialog> section.

Table of Contents

HTML <dialog> Basics
React and <dialog>
React Portal vs <dialog>
Why didn’t we use it before?
Summary

HTML <dialog> Basics

There are two main things we’ll be looking at in this section, that is <dialog> and HTMLDialogElement.

The <dialog> element in HTML is a dialog box or an interactive component. It is a native HTML solution for creating modals and tooltips. The important part is that it comes with an open attribute.

The open attribute in the <dialog> element is a boolean attribute that indicates whether the dialog is active and can be interacted with.

In JavaScript, we interact with this element through the HTMLDialogElement interface, which provides these three methods to manage the dialog.

  • show()
  • showModal()
  • close()

However, it’s recommended to use the show(), showModal()and close()methods to control the visibility of the dialog instead of directly manipulating the open attribute.

When you call the show() or showModal() methods on a <dialog> element, the browser adds the open attribute to the element, making it visible on the screen.

Conversely, when you call the close() method, the browser removes the open attribute, hiding the dialog.

However, these methods provide additional functionalities.

For instance, showModal() makes the dialog modal, which means it will also apply a backdrop to the rest of the page and prevents interaction with the rest of the page until the dialog is closed.

This behavior is not achievable by simply toggling the open attribute.

Another thing is when a <dialog> element is opened using the showModal() method, it implicitly sets aria-modal="true". This indicates that the dialog is modal, and it's expected to be the only element the user interacts with until it's closed.

On the other hand, if a <dialog> element is opened using the show() method or by manually setting the open attribute, or by changing the default display property of the <dialog>, it will implicitly set aria-modal="false".

This indicates that the dialog is non-modal, meaning the user can interact with other elements on the page while the dialog is open.

To simply summarize the difference between the two “show” methods:

1) When to use showModal()?

  • When creating full page modal that doesn’t allow interaction outside of the modal.

2) When to use show()?

  • When creating tooltip that doesn’t block the interaction.

Try it out in this very simple example.

Think about how amazing that is!

Without using the <dialog>, showModal() and show() we would have to create these functionalities ourselves using additional HTML, CSS and Javascript. Then make sure everything is working as intended. That would be very annoying and time-consuming.

React and <dialog>

Now that we’ve seen how the <dialog> element works in vanilla JavaScript, let's see how we can use it in a React application.

The key to using <dialog> in React is the useRef hook, which allows us to access the DOM elements directly.

Here’s the same very simple example like before, but this time using React.

In this example, we use the useRef hook to create a reference to the <dialog> elements. We then assign these references to the ref attribute of the <dialog> elements. This allows us to access the <dialog> elements directly in our event handlers.

The openDialog and closeDialog functions use the showModal and close methods of the dialog reference to open and close the dialog.

Similarly, the showTooltip and hideTooltip functions use the show and close methods of the tooltip reference to show and hide the tooltip.

This way, we can control the visibility of the <dialog> elements in our React component without having to manage any state or use ReactDOM.createPortal.

It's a much simpler and cleaner solution for creating modals and tooltips in React.

ReactDOM.createPortal vs <dialog>

Before the <dialog> element, creating modals in React was a bit more complex. The most common and correct way was to use ReactDOM.createPortal.

This API allows you to render children into a DOM node that exists outside the DOM hierarchy of the parent component.

In the context of modals, ReactDOM.createPortal is used to append the modal component directly to the body element or another container outside the main React application. Doing this avoids CSS stacking context issues and makes the modal appear on top of other elements.

However, using ReactDOM.createPortal requires you to manage the state of the modal (whether it's open or closed) and handle the appending and removing of the modal component from the DOM. This adds unnecessary complexity and might cause additional re-renders.

On the other hand, the <dialog> element simplifies this process since it’s a native HTML solution that doesn’t require any additional state management or DOM manipulations.

Why didn’t we use it before?

Believe it or not, the <dialog>element has been around for quite a while.

Chrome and Opera added support for this element back in 2014, but there were a few major browsers and platforms that didn’t support it, and some of them until fairly recently.

Desktop Safari, desktop Firefox, and Safari iOS (which means all iOS browsers since they have to be based on the WebKit engine) started supporting the <dialog> around March 2022.

Browsers on Android added support in 2023.

If we combine them all, that is a pretty big chunk of market share and users that weren’t able to use this element.

But finally, that’s in the past and after almost 10 years 🤦‍♂️ we can finally use simple and browser-native modals / tooltips.

Summary

In this article, we’ve explored the <dialog> element, a native HTML solution for creating modals and tooltips.

We’ve seen how it simplifies the process of creating these interactive components, eliminating the need for additional HTML, CSS, and JavaScript.

We’ve also seen how it can be used in a React application using the useRef hook, providing a simpler and cleaner solution than ReactDOM.createPortal.

Despite being around for quite a while, the <dialog> element has not been widely used due to lack of support in some major browsers. However, with recent updates, it is now supported across all major browsers, making it a viable and efficient option for creating modals and tooltips in your web applications.

--

--

Marek Bombera

Hi 👋 I'm Marek a Front-end developer from Prague, Czechia. I like newest tech and web3 world. See my work at: https://marekbombera.dev