Refactoring to use Headless UI
The first step is to replace the parent most div of the
Modal to use the
Dialog component, and pass the
Simon Vrachliotis: 0:00 Let's convert our component to a Headless UI Dialog component. It's already imported at the top here, and I'll scroll down, and all I need to do is replace the parent most div with the Dialog component. Now I will pass the open and onClose props to the Dialog component, and with just that we should already have greatly improved our modal component.
0:22 If I open the dialog now, and then try to scroll down the page, I promise you I am scrolling on that wheel, nothing is happening, the body scroll is locked. If I start tabbing through the focusable elements, you can see that the focus remains trapped within the modal, we never focus on the body background element. This is great.
0:40 Let's try to close the modal using the keyboard. I'm going to hit the escape key in three, two, one, bling! You can see that it worked perfectly. This was a huge win, and well worth the minimal effort of converting a div to a Dialog component.
0:54 We can even further simplify our implementation if we go to the page where we're using that modal. Check this out. Right now, we have this isOpen piece of state, and then we conditionally show the modal based on the piece of state. We can get rid of this isOpen check. The modal component will be able by itself to decide whether or not it should be showing.
1:13 If I save this, we have simplified the logic here, and everything still works perfectly. This is a great start. Let's now look at the things we can still improve. If I open the dialog and try to close it by clicking outside the modal, nothing is happening, the modal is not closing.
1:29 We can improve this by making the component aware of this panel area. In the modal component, if I scroll down here, you can see the modal panel, which is this panel. We're going to replace this div with Dialog.Panel, so that now Headless UI knows what is considered outside the panel. When I click on it, it will close the modal. Great.
1:51 The last improvement we'll do is replace the h2 here with the Dialog.Title component. You can see right now we're using a simple h2 tag with no other attributes.
2:00 By converting this to a Dialog.Title, you won't see any difference, but if I go in the browser and open the DevTools, you can see we're still using an h2 element, which is the default, but we also have extra attributes like an id here. If I scroll up, you can see our modal wrapper is using the area labeled by pointing to that id.
2:19 With very minimal effort, we've made our modal components more accessible and more usable. Now we have solid foundations in place to start thinking about implementing multiple style variants with Tailwind CSS.