ReactHustle

How to Implement a Reusable Responsive Modal in React with DaisyUI

Jasser Mark Arioste

Jasser Mark Arioste

How to Implement a Reusable Responsive Modal in React with DaisyUI

There are many ways to create modals in react. In this tutorial, we're gonna show you how to create a responsive modal using DaisyUI that works for both mobile and desktop. We'll make a reusable modal, it can have different content can be different but the layout stays the same. Below is an example of the final output.

What makes a good modal? #

A responsive modal is a good modal. For example in mobile, if you have an login or one-time password (otp) form, the modal should be at the bottom of the screen. But for desktop it should be at the center. The fields should be automatically focused.

Why use daisyUI for styling? #

I really like Daisyui coupled with Tailwindcss because of its versatility or flexibility. You can use it in any project, even if you have MaterialUI.

It has a class modal-bottom and modal-center which just makes it easy for our use case.

Okay, with that out of the way, lets get started!

Project Setup #

Let's setup daisyui + tailwindcss in our project. I'm using a next.js project with typescript. If you're using a different setup, check how to install daisyui here

yarn add tailwindcss autoprefixer postcss daisyui
1

Add tailwindcss.config.js  (make sure to include daisyui in the plugins) and postcss.config.js in the root directory of our project.

// tailwindcss.config.js
/** @type {import('tailwindcss').Config} */
module.exports = {
  content: [
    "./pages/**/*.{js,ts,jsx,tsx}",
    "./components/**/*.{js,ts,jsx,tsx}",
  ],

  theme: {
    container: {
      center: true,
      padding: {
        DEFAULT: "1rem",
      },
    },
  },
  plugins: [require("daisyui")],
};
123456789101112131415161718
// postcss.config.js

module.exports = {
  plugins: ["tailwindcss"],
};
12345

Add tailwind classes in our globals.css

@tailwind base;
@tailwind components;
@tailwind utilities;

html,
body {
  padding: 0;
  margin: 0;
  font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
    Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}

a {
  color: inherit;
  text-decoration: none;
}

* {
  box-sizing: border-box;
}
1234567891011121314151617181920

Let's do a test run if we installed it properly. First we test some classes in index.tsx

import type { NextPage } from "next";

const Home: NextPage = () => {
  return (
    <div className="container">
      <h1 className="text-2xl">Hello world</h1>
      <button className="btn btn-primary">Hello</button>
    </div>
  );
};

export default Home;
123456789101112

Next is run the project

yarn dev
1

Current output:

Current output after installing daisyUI. looks good!

Creating the modal #

Now that we're done installing the dependencies, lets create the responsive modal component.

Inside components folder, let's create a file Modal.tsx

//Modal.tsx
import React from "react";

type Props = {
  children: React.ReactNode;
};

const Modal = ({ children }: Props) => {
  return (
    // we add modal-bottom and modal-middle classes to make it responsive
    //add modal-open for now to test the modal
    <div className="modal modal-bottom sm:modal-middle modal-open">
      {/* we want any content for this modal layout so we just pass the children */}
      <div className="modal-box">{children}</div>
    </div>
  );
};

export default Modal;

12345678910111213141516171819

Let's use it in index.tsx

//index.tsx
import Modal from "components/Modal";
...
      <Modal>
        <h3 className="font-bold text-lg">
          Congratulations random Internet user!
        </h3>
        <p className="py-4">
          You havve been selected for a chance to get one year of subscription
          to use Wikipedia for free!
        </p>
        <div className="modal-action">
          <label className="btn btn-primary">Yay!</label>
        </div>
      </Modal>
....
12345678910111213141516

Let's see how it looks in action in both desktop and mobile:

Modal for desktop

How the modal looks for desktop

Modal for mobile

How the modal looks for mobile

Awesome!, Looks pretty good already!  It even has the backdrop.

Implementing the open/close state #

There are many ways in DaisyUI to open/close a modal just by using pure html. However, in this tutorial we're using a react approach where we control the state of the modal and use toggle classes to hide/show the modal. First lets install classnames package to easily organize the classes

yarn add classnames
1

Let's modify our Modal.tsx component to add an open state and modify the className to that it makes use of classnames:

//Modal.tsx
import React from "react";
import cn from "classnames";
type Props = {
  children: React.ReactNode;
  open: boolean;
};

const Modal = ({ children, open }: Props) => {
  const modalClass = cn({
    "modal modal-bottom sm:modal-middle": true,
    "modal-open": open,
  });
  return (
    <div className={modalClass}>
      <div className="modal-box">{children}</div>
    </div>
  );
};

export default Modal;
123456789101112131415161718192021

Let's implement open/close functionality by pressing a button in index.tsx

//index.tsx
...
const Home: NextPage = () => {
  //add state and a toggle handler
  const [open, setOpen] = useState(false);
  const handleToggle = () => setOpen((prev) => !prev);
  return (
    <div className="container">
      <h1 className="text-2xl">Hello world</h1>
      {/* opens the modal */}
      <button className="btn btn-primary" onClick={handleToggle}>
        Hello
      </button>
      <Modal open={open}>
        <h3 className="font-bold text-lg">
          Congratulations random Internet user!
        </h3>
        <p className="py-4">
          You havve been selected for a chance to get one year of subscription
          to use Wikipedia for free!
        </p>
        <div className="modal-action">
          {/* closes the modal */}
          <button className="btn btn-primary" onClick={handleToggle}>
            Yay!
          </button>
        </div>
      </Modal>
    </div>
  );
};
...
1234567891011121314151617181920212223242526272829303132

Let's see it in action!

Adding open/close state to the modal

Implementing click-outside functionality #

Currently our modal only closes by pressing the "Yay!" button. Let's add a close functionality when user clicks outside the modal. We do this by adding a disableClickOutside props setting. For this setting we enable click-outside by default and add disableClickOutside when we want to disable it. We'll also be using useOnClickOutside hook from  usehooks-ts package.

First lets install usehooks-ts

Side note: usehooks-ts is a useful library that contains many custom hooks for typescript. be sure to check it out!

#I'm using 2.6.0 since 2.7.1 has a breaking change and needs to upgrade node.js
yarn add usehooks-ts@2.6.0
12

Let's modify our Modal.tsx component and implement click-outside functionality:

...
import { useOnClickOutside } from "usehooks-ts";
type Props = {
  children: React.ReactNode;
  open: boolean;
  // add disableClickOutside
  disableClickOutside?: boolean;
  //add onClose event so that we can close the modal from inside the component
  onClose(): void;
};

...
const Modal = ({ children, open, disableClickOutside, onClose }: Props) => {
  const ref = useRef(null);
  useOnClickOutside(ref, () => {
    if (!disableClickOutside) {
      onClose();
    }
  });

  const modalClass = cn({
    "modal modal-bottom sm:modal-middle": true,
    "modal-open": open,
  });
  return (
    <div className={modalClass}>
      <div className="modal-box" ref={ref}>
        {children}
      </div>
    </div>
  );
};
...
123456789101112131415161718192021222324252627282930313233

When calling the Modal component in index.tsx, we can modify it if we want to enable or disable clickoutside


//click outside enabled
<Modal open={open} onClose={handleToggle}>
//click outside disabled
<Modal open={open} onClose={handleToggle} disableClickOutside>
12345

Let's see it in action (Modal with click outside enabled)

Modal with clickOutside enabled

Conclusion #

We've successfully created a working responsive modal in react by using DaisyUI. The modal can handle any content and we're able to successfully toggle it inside a parent component. 

If you like more tutorials like this on react and daisyUI, be sure to sign up to our newseletter!

Resources: #


Credits: Image by Rahul Yadav from Pixabay

Share this post!

Related Posts

Disclaimer

This content may contain links to products, software and services. Please assume all such links are affiliate links which may result in my earning commissions and fees.
As an Amazon Associate, I earn from qualifying purchases. This means that whenever you buy a product on Amazon from a link on our site, we receive a small percentage of its price at no extra cost to you. This helps us continue to provide valuable content and reviews to you. Thank you for your support!
Donate to ReactHustle