You may hear developers talking about dialogs and modals on websites as being similar things. Are they really the same though? The answer is: sort of. Modals are a type of dialog, but not all dialogs are modals. They do have similar appearances and functionality, but with a key difference. In this blog post, I'll explore modals and dialogs and explain the difference while showing you how they can be used natively in the browser.
Please note: I will be using the term "dialog" to represent a non-modal dialog and the term "modal" to represent a modal dialog. This is to describe the behavior of each rather than the HTML element to build them.
Dialogs and modals?
While both dialogs and modals can appear similar, there are different reasons for using each. First we'll discuss what they are and how they're used and then we'll discuss how they're different.
How are dialogs and modals similar?
Dialogs and modals can serve similar purposes: to display some data or collect some data outside the flow of the normal document. This could be a form collection, a call-to-action, or something similar that you want to be front-and-center for a user. Typically, people refer to these things as "popups".
I'm sure you've seen them all over the web if you've been using the internet for any amount of time. Typically, people complain about these because they can be disruptive when using a website. Because of this, it's important to use them in this fashion sparingly. One of the two items is more disruptive than the other though...
How are dialogs and modals different?
The way in which dialogs and modals differ has to do with how it allows the user to interact with the document when it's open. What does that mean? Let's talk about each one:
- A dialog still allows a user to interact with other content on the page while it's open (i.e. click buttons and links visible around the dialog)
- A modal locks down the page until something is done. This is typically done with a background that covers all other content so the modal must be dealt with. This is the more disruptive of the two options.
Understanding the differences between the two will allow you to make the right choice about which option is best for your situation. As a general rule, you should reach for the dialog unless it's absolutely necessary to prevent the user from interacting with other elements.
The dialog element
In years past, building dialogs and modals consisted of nesting divs inside of divs while applying some styles to make it look and behave a certain way using javascript and css. While some of this is still necessary due to it's interactive nature, the dialog has come a long way since then.
One of the big problems around the dialog components of old are a lack of accessibility. They just weren't easy to understand and use with screen readers. There was a role="dialog" attribute which could be applied, but many times accessibility is unfortunately an afterthought.
Despite this, the web has evolved quite a bit in the last several years to make accessibility much more "baked in" through the use of semantic elements. Because of this, we have a dialog element in HTML5 which takes care of a lot of these things for us. In addition to being accessible, the dialog element gives us the ability to use it as both a dialog and a modal, although the way to do this may not be super intuitive.
Dialog element basics
A dialog element is hidden by default and accepts children to be displayed inside the dialog. It also accepts an open attribute which decides whether the dialog should be visible to the user or not. Past that, it's got all the same attributes you would expect on a generic HTML element (class, id, aria-stuff, etc).
How do I use a dialog?
Now that we've discussed what attributes a dialog element can have, we should probably talk about how to actually use the thing. I mentioned that there is an open attribute available on a dialog element. By changing this value, you can show and hide the dialog box. That's great, but how do you actually do that? First, lets create a function which toggles the dialog between open and closed:
const toggleDialog = () => {
// Get the dialog element
const dialog = document.getElementById("dialog");
// Figure out what the 'open' attribute is set to
const open = dialog.getAttribute("open");
// Set the dialog's 'open' value accordingly
if (open) {
dialog.removeAttribute("open");
} else {
dialog.setAttribute("open", "true");
}
};
When using HTML, the dialog will be shown if the open attribute is present, regardless of what the value is. In the function above, I am looking to see if the dialog has the open attribute set. If so, it removes the attribute but if the open attribute is missing, it adds it with a value of true.
Next, I will create the dialog itself. For now, I will just create a basic dialog element with some content inside:
<dialog id="dialog">I'm a dialog</dialog>
Finally, I want a button the user can click to control the dialog. Clicking the button once will show the dialog and clicking the button a second time will hide the dialog.
<button onclick="toggleDialog()">This button toggles a dialog</button>
Once this is built out, your result should look something like this:
How do I use a modal?
Although my HTML code will be the same for the modal (except for the dialog ID), the function being called will be different for a modal. This is because the browser provides a method which comes built-in to handle the modal's behavior. Unlike the dialog, a modal requires two separate buttons to handle opening and closing the dialog. This is because any buttons outside the dialog will be inaccessible while it is open. Because of this difference, I will create functions for each task:
const openModal = () => {
// Get the modal element
const modal = document.getElementById("modal");
// Call the built-in 'showModal' method to display the modal
modal.showModal();
};
const closeModal = () => {
// Get the modal element
const modal = document.getElementById("modal");
// Call the built-in 'close' method to close the modal
modal.close();
};
The button and dialog should look pretty much the same as the previous code except for an additional button to close the modal:
<button onclick="openModal()">This button opens a modal</button>
<!--The dialog element being used as a modal-->
<dialog id="modal">
<p>I'm a modal</p>
<!-- A button to be able to close the modal -->
<button onclick="closeModal()">Close</button>
</dialog>
With this code in place, clicking the button should display something like this:
The ::backdrop pseudoselector
You may notice that a key difference between the dialog and modal is a backdrop which covers all of the content behind the modal. This is what makes a modal different because it prevents the user from accessing the page content until the modal is closed. This backdrop doesn't look very interesting though. Lucky for us, there is a pseudoselector that can be used to target and style the backdrop so it better matches your use case. You can use the ::backdrop pseudoselector like this:
dialog::backdrop {
background: #111111;
}
It's worth noting that the backdrop only appears on modals, so the pseudoselector will not have any impact on the dialogs you're displaying.
Accessibility
I mentioned earlier that accessibility is a big benefit we get from the dialog element in HTML5, but what does that mean? There is a role="dialog" attribute which can be assigned to an element to tell a screen reader that the item is a dialog. In addition, an aria- tag should be added to tell the screen reader whether the element is visible or not.
<div role="dialog" aria-hidden="true">
<p>This is a dialog</p>
</div>
By using the dialog element, the browser takes care of these things for us! So instead of the code above, we can simply write:
<dialog>
<p>This is a dialog</p>
</dialog>
While the two attributes may not seem like a big deal, it may not always be something you think of when you create a dialog or modal. Using a dialog element allows us to focus on building cool things instead of getting into the nitty gritty and sometimes guessing on which aria- attributes are appropriate.
Making my dialogs cool
As previously discussed, my dialogs are pretty lame. I think it's time to add some styles. In the spirit of Max Goof, let's build a modal he might have looked at for his favorite singer, Powerline. First, I'll set some CSS variables based on some of the palettes I've seen online:
:root {
--background: #111;
--text: #fff;
--yellow: #d1933f;
--red: #9b2a4e;
--purple: #7044a5;
}
Now that I have some colors ready to go, it's time to start styling. Here's some styles I'm using for all the things that aren't the dialogs:
html,
body {
height: 100%;
width: 100%;
margin: 0;
padding: 0;
}
body {
font-family: sans-serif;
color: var(--text);
text-align: center;
position: relative;
display: flex;
align-items: center;
justify-content: center;
}
body:before {
content: "";
display: block;
position: absolute;
inset: 0;
background-image: url("/bg.jpg");
background-size: cover;
background-position: top center;
z-index: -1;
}
body:after {
content: "";
display: block;
position: absolute;
inset: 0;
background: radial-gradient(transparent, black);
z-index: 0;
line-height: 1.5rem;
}
main {
position: relative;
z-index: 1;
}
a {
color: var(--text);
background: var(--red);
padding: 0.25rem;
text-decoration: none;
transition: background 0.3s;
}
a:hover {
background: linear-gradient(
to bottom right,
var(--yellow),
var(--red),
var(--purple)
);
}
button {
background: var(--yellow);
font-size: 1.1rem;
padding: 0.5rem;
margin: 1rem;
border: 2px solid var(--red);
border-radius: 8px;
cursor: pointer;
}
button:hover {
box-shadow: 0 0 1rem var(--red);
}
.headline {
font-size: 1.5rem;
font-weight: bold;
text-transform: uppercase;
color: var(--text);
text-shadow: 5px 5px 0 var(--red);
}
I would like to style the dialog as well as the backdrop according to the palette I've chosen so it doesn't stick out like a sore thumb. Below are the styles I'll be using for the dialog:
dialog {
position: fixed;
background: linear-gradient(
to bottom right,
var(--yellow),
var(--red),
var(--purple)
);
margin: 0 auto;
text-align: center;
width: 400px;
top: 50%;
transform: translateY(-50%);
border-radius: 8px;
border: 1px solid var(--purple);
}
dialog::backdrop {
background: rgba(74, 62, 89, 0.4);
}
Now my modal looks like this:
You can see the full code for this at https://github.com/iamtimsmith/dialog-vs-modal and you can visit the finished site at https://dialog-vs-modal-nine.vercel.app
Conclusion
Dialogs and modals have become a common part of the web, but it's not always clear which one is appropriate for a given situation. Now you'll know that a dialog is used when the user should still be able to interact with the main page content, while a modal should be used when the dialog should prevent the user from accessing the rest of the page. With this in mind, you can hopefully build better and more accessible user experiences when using a popup.
Have questions? You can find me on Twitter at @iam_timsmith.
Top comments (4)
Hey I don't think you got the terminology quite right.
"Modal" is a qualifier for a dialog (ie a dialog can be modal or non-modal), not a standalone thingy.
IMHO the premise is misleading. "Dialog vs modal" should be "(non-modal) dialog vs modal dialog" IMO.
developer.mozilla.org/en-US/docs/W...
For example you write "Below are the styles I'll be using for the dialog" followed by "Now my modal looks like this".
IMO you should still describe the use cases and differences between non-modal and modal dialogs, but I think you should change the title and be more specific with the terminology to not cause confusion. After all you're trying to teach others here.
Have a nice day!
@bwin I appreciate your feedback and agree with your point. I have updated the article to reflect the better terminology of modal and non-modal dialogs.
great topic choice š this is something i really think deserves more attention. way to spread the word!
Thanks it's been a mystery for me for a while, it's nice to see someone get in to this topic in depth. š