dialog
elementDialogs are an integral part of any user interface, be it the web, mobile, or any other that exists today.
Do you want to confirm something from the user? You present the user a dialog with selectable options. Do you want to gather info from the user? You use a dialog with a submittable form input. There are numerous use cases when it comes to using the dialog in your UIs.
You can use dialogs by installing JavaScript libraries in your project, and these are available in any kind of framework you’re using. For instance, if your project is in React, you can use the react-aria-modal. For Angular, you can use ngx-smart-modal. Or if you’re working with good old jQuery, you can use jquery-modal.
Third-party libraries are great, but they do come with an additional overhead to your project that not only adds a certain amount of complexity but also increases the overall bundle size of your app.
On top of this, you’re going to install the entire library with all the bells and whistles even if you’re only going to use certain features of that library. This is not great in my opinion.
That’s where the browser’s native <dialog>
element comes into play. It’s everything you’ll ever want in a dialog, and now that Safari has added the support for the <dialog>
element starting v15.4, there isn’t any excuse not to use them in production!
<dialog>
element?<dialog>
is an HTML element that represents a dialog box such as alert, confirmation, inspector, or subwindow.
A very basic <dialog>
element would look like so:
<dialog> Hey, this is an HTML dialog! </dialog>
Since the <dialog>
wouldn’t be visible by default, we would need to pass in an open
property to make it visible:
<dialog open> Hey, this is an HTML dialog! </dialog>
Here’s how it would look:
See the Pen
The basic <dialog> by Amit Merchant (@amit_merchant)
on CodePen.
<dialog>
’s appearanceYou might be wondering, where does that black border in the example come from? The answer is every user agent (browser) would apply a default style to the <dialog>
element that would look something like this:
The dialog’s design can be easily customized. For instance, if you want to remove the default border and add a drop shadow instead and a few more niceties, here’s how you can do it:
dialog { border: none; box-shadow: #00000029 2px 2px 5px 2px; border-radius: 10px; padding: 30px; background-color: pink; font-family: sans-serif; font-size: 20px; font-weight: bold; }
And here’s how the customized dialog would look:
See the Pen
Customising <dialog> by Amit Merchant (@amit_merchant)
on CodePen.
In real-world scenarios, you wouldn’t be using dialog boxes straight-up like this. You may want to trigger the dialog on some action. Let’s say when clicking a button.
Check out this example:
<dialog id="demoDialog"> Hey there! This is a dialog <button id="closeDialog">Close dialog</button> </dialog> <menu> <button id="openDialogButton">Open dialog box</button> </menu>
As you can tell, we have a dialog with an ID demoDialog
. Now, if we want to open this dialog by clicking the Open dialog box button, here’s how we can do it:
var openDialogButton = document.getElementById('openDialogButton'); var demoDialog = document.getElementById('demoDialog'); var closeDialog = document.getElementById('closeDialog'); // "Open dialog box" button opens the <dialog> openDialogButton.addEventListener('click', function () { if (typeof demoDialog.showModal === "function") { demoDialog.showModal(); } else { console.log("The <dialog> API is not supported by this browser"); } }); closeDialog.addEventListener('click', function() { demoDialog.close(); })
To open the dialog, we can programmatically call the showModal()
method on the <dialog>
instance through JavaScript. But before that, it would be nice to first check whether the browser supports the <dialog>
or not by checking if showModal
exists in the dialog’s object.
We can call the close()
method on Close dialog to close the <dialog>
.
N.B., you can close the <dialog>
using the Esc key as well.
Here’s everything in action:
See the Pen
Opening a <dialog> programatically by Amit Merchant (@amit_merchant)
on CodePen.
If you want to handle user-entered input from within the <dialog>
, you can define a <form>
inside it and set its method
as "dialog"
.
<dialog id="collectEmail"> <form method="dialog"> <p> <label> Email: <input type="email" name="email" id="email" placeholder="Enter your email"> </label> </p> <menu> <button value="cancel">Cancel</button> <button id="confirmBtn" value="default">Confirm</button> </menu> </form> </dialog> <menu> <button id="openEmailDialog">Submit user's email</button> </menu> <output aria-live="polite"></output>
When the form is submitted, the dialog will close automatically, and then, you can handle the input value on the dialog’s close
event like so:
collectEmail.addEventListener('close', function() { let email = document.getElementById('email').value; outputBox.innerHTML = `User's email: <b>${email}</b>`; });
Putting it all together:
See the Pen
<dialog> input demo by Amit Merchant (@amit_merchant)
on CodePen.
<dialog>
’s backdropIt’s also possible to change the dialog’s backdrop when it’s opened using the ::backdrop
pseudo CSS property:
dialog::backdrop { background-color: #673ab752; }
Here’s how this would look:
See the Pen
<dialog> backdrop by Amit Merchant (@amit_merchant)
on CodePen.
<dialog>
when clicking outside of itBy default, when the <dialog>
is opened, it cannot be closed when clicking outside of the dialog’s area. If we want to introduce this behavior, we can get the dialog’s DOMRect using the getBoundingClientRect()
on clicking the dialog.
We can then get the coordinates of the click and check if it falls outside of the dialog’s rectangle. And based on this, we can call the dialog’s close()
event like so:
collectEmail.addEventListener("click", event => { const rect = collectEmail.getBoundingClientRect(); if (event.clientY < rect.top || event.clientY > rect.bottom || event.clientX < rect.left || event.clientX > rect.right) { favDialog.close(); } });
Here’s the behavior in action:
See the Pen
<dialog> demo by Amit Merchant (@amit_merchant)
on CodePen.
Try clicking outside of the dialog!
And that’s about it for the native HTML <dialog>
element that has been now widely supported throughout the major browsers including our beloved Safari!
So, this is a no-brainer if you’ve got use cases where you need to use dialogs and you end up using the <dialog>
element. Happy coding!
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowBuild scalable admin dashboards with Filament and Laravel using Form Builder, Notifications, and Actions for clean, interactive panels.
Break down the parts of a URL and explore APIs for working with them in JavaScript, parsing them, building query strings, checking their validity, etc.
In this guide, explore lazy loading and error loading as two techniques for fetching data in React apps.
Deno is a popular JavaScript runtime, and it recently launched version 2.0 with several new features, bug fixes, and improvements […]
3 Replies to "Why you should be using the <code>dialog</code> element"
it’s still not nearly supported enough to use in production, check caniuse – 76%
Hey Karol,
By using it in the production I meant the dialog element is supported by all the modern browsers except a few obscure browsers, such as IE, Opera Mini, KaiOS browser, UC browser etc, that still doesn’t support the dialog element.
The market share of these browsers is fairly low at this point. And that’s why I said it’s safe to use it in the production.
You can use another way that is much simpler for detecting outside click:
“`
const listener = (event: Event) => {
if (
event.target !== collectEmail &&
event.composedPath().includes(collectEmail)
) {
return;
}
// clicked outside the `collectEmail `
};
“`
You’re welcome 🙂