How to Use the Dialog Component with Headless UI and Tailwind CSS

Easily create a dialog component with Tailwind CSS

Photo by Mike Petrucci on UnsplashPhoto by Mike Petrucci on Unsplash

Tailwind CSS is one of the most popular options when it comes to styling React applications. You can easily add styles to your components with utility classes, rather than creating external CSS files.

If you are new to Tailwind CSS, check out this article below to get started.

Tailwind helps with basic styling, but sometimes you will need to create more complex components, like a dialog. Instead of creating a new component from scratch, the team at Tailwind has released Headless UI.

Headless UI is a library of:

“Completely unstyled, fully accessible UI components, designed to integrate beautifully with Tailwind CSS.”

They currently have support for React and Vue projects for the following 9 components:

  • Menu (Dropdown)

  • List (Select)

  • Switch (Toggle)

  • Disclosure

  • Dialog (Modal)

  • Popover

  • Radio Group

  • Transition

  • Tabs

In this article, we will take a look at the Dialog (Modal) component and learn how to use it in a React project.

Set up

For this example, I will be working in a basic React application started from create-react-app.

Don't forget to install Headless UI into your project as well.

# npm
npm install @headlessui/react

# Yarn
yarn add @headlessui/react

In the App.js file, I will create one state value called isOpen. This value will control whether or not the dialog will be open or closed.

const [isOpen, setIsOpen] = useState(false);

In this component, I will render one button. This button will have an onClick handler that will set the isOpen value to true when clicked.

<button onClick={() => setIsOpen(true)}>Open Dialog</button>

Then, I will render another component called ModalDialog. Don't worry, we have not created this component yet, so you will see an error for now. We will pass two props to this component: open and setIsOpen.

Our App component should currently look something like this.

const App = () => {
  const [isOpen, setIsOpen] = useState(false);

return (
    <div className="flex flex-col h-screen justify-center items-center">
      <ModalDialog isOpen={isOpen} setIsOpen={setIsOpen} />
      <button onClick={() => setIsOpen(true)}>Open Dialog</button>
    </div>
  );
};

What is the Dialog component?

“A fully-managed, renderless dialog component jam-packed with accessibility and keyboard features, perfect for building completely custom modal and dialog windows for your next application.”

Let's take a look at the Dialog component. It is built with 4 components:

  • Dialog — The main component where you can set the open state and handle the onClose function.
  • Dialog.Overlay — Used to create an overlay for the dialog. Clicking on the overlay will dismiss the dialog.
  • Dialog.Title — The title for your dialog. it will set the aria-labelledby on the dialog. The default element is an <h2>.
  • Dialog.Description — The description for your dialog. it will set the aria-describedby on the dialog. The default element is a <p>.

How to use the Dialog component?

I will create a new file called ModalDialog.js. In this file, I will create the ModalDialog component that we previously added to the App.js file.

In this file, I will first import the Dialog component from Headless UI.

import { Dialog } from '@headlessui/react';

Then, I will create the ModalDialog component. Remember, this component took two props, isOpen and setIsOpen. I will render the base Dialog component and pass the following two props to the Dialog component:

  • open — A boolean that controls whether the dialog is open or not.

  • onClose — A function that is called when the dialog is dismissed.

    const ModalDialog = ({ isOpen, setIsOpen }) => {
      return (
        <Dialog open={isOpen} onClose={() => setIsOpen(false)}>
          ...dialog contents
        </Dialog>
      );
    };
    

Next, I will add  `Dialog.Overlay`,  `Dialog.Title`,  `Dialog.Description`, and two buttons inside of the main  `Dialog`  component.

    const ModalDialog = ({ isOpen, setIsOpen }) => {
      return (
        <Dialog open={isOpen} onClose={() => setIsOpen(false)}>
          <Dialog.Overlay />
          <Dialog.Title>Title of dialog</Dialog.Title>
          <Dialog.Description>
            Description of dialog contents.
          </Dialog.Description>
          <button onClick={() => setIsOpen(false)}>Cancel</button>
          <button onClick={() => setIsOpen(false)}>Confirm</button>
        </Dialog>
      );
    };

## Style the Dialog component

If we start up our project and open the dialog, we will see something like this.

![image](https://cdn-images-1.medium.com/max/5120/1*mgHTmtAQHXpKft8c10RlcA.png)

The dialog contents will be showing up at the bottom left-hand corner of the screen. We can easily fix this just by adding some utility classes using Tailwind CSS.

First, we can add a transparent dark background that is typically seen in a modal dialog.

    <Dialog.Overlay className="fixed inset-0 bg-black opacity-30" />

Then, we can add style to the dialog contents. To style the contents of the dialog, you can do so like any other components. In the example below, I added a wrapper <div> to center the contents of the dialog. I also added some basic styles to the title and buttons.

    <div className="flex items-center justify-center min-h-screen">
      <Dialog.Overlay className="fixed inset-0 bg-black opacity-30" />
      <div className="relative bg-white rounded max-w-sm mx-auto p-8">
        <Dialog.Title className="text-xl">
          Title of dialog
        </Dialog.Title>
        <Dialog.Description>
          Description of dialog contents.
        </Dialog.Description>
        <button
          className="border-black border-solid border rounded mx-2 mt-8 py-1 px-2"
          onClick={() => setIsOpen(false)}
        >
          Cancel
        </button>
        <button
          className="border-black border-solid border rounded mx-2 mt-8 py-1 px-2"
          onClick={() => setIsOpen(false)}
        >
          Confirm
        </button>
      </div>
    </div>

Now if we open our dialog, we can see the contents are centered on the screen and there is a transparent background.

![image](https://cdn-images-1.medium.com/max/3556/1*wJIuAFyuAN59t9rR0_c27w.png)

When you click on the overlay of the dialog, it will call the onClose function for us. Accessibility concerns are also taken care of thanks to Headless UI. These are some of the benefits of using these components rather than trying to build them from scratch.

You can check out the full source code for this component below.

<script src="https://gist.github.com/chadmuro/d2c1743eb74fb174dafca1c19daad456.js"></script>

## Conclusion

Thanks for reading! I hope this article was helpful for you to use the Dialog component with Headless UI. I have been enjoying styling my applications with Tailwind CSS, but it can be difficult to create some of the more complex components. That is where Headless UI components can make things a lot easier.

I'm planning to look into more Headless UI components in future articles, so stay tuned!

Enjoyed this article?

Share it with your network to help others discover it

Continue Learning

Discover more articles on similar topics