One of the reasons I end up pulling in a UI library to my projects is often dialogs. They were always, not really a mystery, but something I really didn't think about much and just accepted as probably really hard to implement. Turns out, there are elements and methods right there in HTML, CSS, and JavaScript already there and ready for us to use. So let's take a look at how we would create and style a dialog without the use of a library.
Functionality
The contents of our dialog are going to go into a <dialog>
element. By using this element, rather then a <div>
, we gain access to a lot of built in functionality and accessibility features already baked in for us. Some of these features are the open
attribute and some default styles. Let's create our dialog and a button that we will use to open it (Listing 1).
Notice in figure 1 that when we run this code, all we see is the button. The dialog is closed by default.
Next let's add the JavaScript so that we can open and close our dialog (listing 2).
The showDialog()
and close()
methods are part of the HTMLDialogElement
interface which is used by the <dialog>
element. showDialog()
displays the dialog on the top layer and includes a backdrop that we can style using the ::backdrop
pseudo-element (more on that a little bit later in this article). close()
as its name implies, closes the dialog. Figure 2 shows our open dialog.
Note: Notice that pressing the escape key also closes the dialog even though we didn't have to write any code for that. One of the many benefits of using semantic tags is that they come along with baked-in behaviors; this is one of them for dialogs.
We now have a mechanism to open and close our dialog, which means we can see it and start to style it.
Styles
Let's start by setting some custom properties for our theme colors and styling our typography and buttons. Next we will style the dialog and backdrop itself. Listing 3 shows our theme styles.
Our page now looks as seen in figure 3.
With the general theme out of the way, let's focus on styling the actual dialog elements starting with the backdrop.
The backdrop does not inherit from anything, we therefore must add it as a selector to our rule that contains all of our custom properties if we want to be able to use them on our backdrop (listing 4).
Now that we can use our custom properties on the backdrop, let's go ahead and change its background color to use the --backdrop
custom property and give it a bit of a blur as seen in listing 5.
With the backdrop styled (figure 4), let's focus on the dialog itself.
Let's make it so that when our dialog content is larger than our screen (figure 5), instead of the entire dialog contents scrolling, we keep our header and footer visible and only scroll the body section. To do this we will use grid.
We can't just give our dialog a display
of grid
because otherwise, when it is suppose to be closed it becomes visible on the screen (figure 6). We can only change the display
property value of the dialog when it is open.
We therefore use a selector attribute: dialog[open]
. When the dialog is open, the browser automatically gives it an attribute of open and then removes it once closed. We can therefore use this attribute in our selector, to only change the display property value when the dialog is open. Our CSS therefore looks as follows (listing 6).
By setting the width and the height, and then giving the body section a vertical overflow of auto, the header and footer now stay in view but the center section scrolls (figure 7).
However, our scroll-bar is inset due to the default padding the browser gives the dialog. The sections also blend into each other a bit so let's adjust the padding and add a little bit of polish to it's contents.
To make it more obvious that this is a dialog, we are also going to replace the border with a drop shadow so that it seems like it is floating above the backdrop.
Listing 7 shows our finishing touches.
Our finished dialog looks as seen in figure 8. By giving the header a background color and adding shadows to the header and footer, the content portion of the dialog becomes more distinct. The scroll bar is also now better positioned at the edge of the dialog. Finally the shadow given to the dialog itself creates a cense of depth to the design.
And just like that we have a functioning, styled dialog and we were able to do it using functionality already available in HTML, CSS, and JavaScript.
You can find a running version of the code presented on codepen at https://codepen.io/martine-dowden/pen/BaGLeJW.
Happy Coding!