How to Create a Modal in React
Tags: react, beginners, javascript, node
Published: 2021-08-21 11:06:23

One of the most used components in React is undoubtedly modals because they can be used in different contexts, from messages to user input.

Like many other components in React, a dependency can be installed that helps in this process, however we always end up being limited in several ways and one of them is styling.

For this reason I had the idea to create in this article, we are going to use the knowledge we already know, from css, props and hooks.

# Let's code

Today the only thing we are going to install is an icon library to make it easier to use (however the same works if you use webfonts):

```sh
npm install react-icons
```

Now we can immediately start working on our `Modal.jsx`. But first let's talk about CSS.

One of the classes we're going to have is called `.darkBG` that's because once the modal is open I'll add a background color to slightly hide all the other components that are on the page. This is to focus the user's attention only on the modal.

Then our component will be divided into three areas, the first one will be the header, where you can put the modal title. The second part will be the content, here you can put the message you want. 

The third and last part will be the actions that can be performed in the modal, that is, cancel the modal in order to close it and another action (save, update, delete, etc).

Now that we have a few notions in mind, you can copy this same css (you can play freely with it to customize your modal):

```css
/* @src/components/Modal.module.css */

.darkBG {
  background-color: rgba(0, 0, 0, 0.2);
  width: 100vw;
  height: 100vh;
  z-index: 0;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
  position: absolute;
}

.centered {
  position: fixed;
  top: 50%;
  left: 50%;
  transform: translate(-50%, -50%);
}

.modal {
  width: 250px;
  height: 170px;
  background: white;
  color: white;
  z-index: 10;
  border-radius: 16px;
  box-shadow: 0 5px 20px 0 rgba(0, 0, 0, 0.04);
}

.modalHeader {
  height: 50px;
  background: white;
  overflow: hidden;
  border-top-left-radius: 16px;
  border-top-right-radius: 16px;
}

.heading {
  margin: 0;
  padding: 10px;
  color: #2c3e50;
  font-weight: 500;
  font-size: 18px;
  text-align: center;
}

.modalContent {
  padding: 10px;
  font-size: 14px;
  color: #2c3e50;
  text-align: center;
}

.modalActions {
  position: absolute;
  bottom: 2px;
  margin-bottom: 10px;
  width: 100%;
}

.actionsContainer {
  display: flex;
  justify-content: space-around;
  align-items: center;
}

.closeBtn {
  cursor: pointer;
  font-weight: 500;
  padding: 4px 8px;
  border-radius: 8px;
  border: none;
  font-size: 18px;
  color: #2c3e50;
  background: white;
  transition: all 0.25s ease;
  box-shadow: 0 5px 20px 0 rgba(0, 0, 0, 0.06);
  position: absolute;
  right: 0;
  top: 0;
  align-self: flex-end;
  margin-top: -7px;
  margin-right: -7px;
}

.closeBtn:hover {
  box-shadow: 0 5px 20px 0 rgba(0, 0, 0, 0.04);
  transform: translate(-4px, 4px);
}

.deleteBtn {
  margin-top: 10px;
  cursor: pointer;
  font-weight: 500;
  padding: 11px 28px;
  border-radius: 12px;
  font-size: 0.8rem;
  border: none;
  color: #fff;
  background: #ff3e4e;
  transition: all 0.25s ease;
}

.deleteBtn:hover {
  box-shadow: 0 10px 20px -10px rgba(255, 62, 78, 0.6);
  transform: translateY(-5px);
  background: #ff3e4e;
}

.cancelBtn {
  margin-top: 10px;
  cursor: pointer;
  font-weight: 500;
  padding: 11px 28px;
  border-radius: 12px;
  font-size: 0.8rem;
  border: none;
  color: #2c3e50;
  background: #fcfcfc;
  transition: all 0.25s ease;
}

.cancelBtn:hover {
  box-shadow: none;
  transform: none;
  background: whitesmoke;
}
```

As you can see, the css classes are all very simple, now we can start working on our `Modal.jsx`.

```js
// @src/components/Modal.jsx

import React from "react";

const Modal = () => {
  return <h1>Hello Modal</h1>;
};

export default Modal;
```

One of the first things we're going to add is our styles and in this article we're going to use css modules.

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";

const Modal = () => {
  return <h1>Hello Modal</h1>;
};

export default Modal;
```

In our modal we will have to have a close button and for that we will need an icons, this way we will import the icon that will be used:

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";
import { RiCloseLine } from "react-icons/ri";

const Modal = () => {
  return <h1>Hello Modal</h1>;
};

export default Modal;
```

One thing I want you to keep in mind is that we're going to have to receive props so we can close the modal as soon as it's open. So we will receive a single props which will be a function called `setIsOpen()`.

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";
import { RiCloseLine } from "react-icons/ri";

const Modal = ({ setIsOpen }) => {
  return <h1>Hello Modal</h1>;
};

export default Modal;
```

With all that done we can start working on our template. First we'll add our dark background to give the modal more emphasis when it's open.

As soon as the user clicks on the dark background, we'll want to close the modal, so we'll add the `onClick` react event and pass a boolean as the only argument of the `setIsOpen()` function (which in this case will be `false`).

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";
import { RiCloseLine } from "react-icons/ri";

const Modal = ({ setIsOpen }) => {
  return (
    <>
      <div className={styles.darkBG} onClick={() => setIsOpen(false)} />
      // ...
    </>
  );
};

export default Modal;
```

Now we're going to work on our modal, so we're going to add the wrapper to center the modal on the screen (`.centered`), as well as the body of our modal (`.modal`) and its header (`.modalHeader`).

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";
import { RiCloseLine } from "react-icons/ri";

const Modal = ({ setIsOpen }) => {
  return (
    <>
      <div className={styles.darkBG} onClick={() => setIsOpen(false)} />
      <div className={styles.centered}>
        <div className={styles.modal}>
          <div className={styles.modalHeader}>
            <h5 className={styles.heading}>Dialog</h5>
          </div>
          // ...
        </div>
      </div>
    </>
  );
};

export default Modal;
```

Now we can add the button that will contain the icon to close the modal, which will contain an `onClick` event as well as pass the `setIsOpen()` function as `false` so that we can close the modal as soon as this button is clicked.

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";
import { RiCloseLine } from "react-icons/ri";

const Modal = ({ setIsOpen }) => {
  return (
    <>
      <div className={styles.darkBG} onClick={() => setIsOpen(false)} />
      <div className={styles.centered}>
        <div className={styles.modal}>
          <div className={styles.modalHeader}>
            <h5 className={styles.heading}>Dialog</h5>
          </div>
          <button className={styles.closeBtn} onClick={() => setIsOpen(false)}>
            <RiCloseLine style={{ marginBottom: "-3px" }} />
          </button>
          // ...
        </div>
      </div>
    </>
  );
};

export default Modal;
```

Now we can add the content of our modal (`.modalContent`) and add a message.

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";
import { RiCloseLine } from "react-icons/ri";

const Modal = ({ setIsOpen }) => {
  return (
    <>
      <div className={styles.darkBG} onClick={() => setIsOpen(false)} />
      <div className={styles.centered}>
        <div className={styles.modal}>
          <div className={styles.modalHeader}>
            <h5 className={styles.heading}>Dialog</h5>
          </div>
          <button className={styles.closeBtn} onClick={() => setIsOpen(false)}>
            <RiCloseLine style={{ marginBottom: "-3px" }} />
          </button>
          <div className={styles.modalContent}>
            Are you sure you want to delete the item?
          </div>
          // ...
        </div>
      </div>
    </>
  );
};

export default Modal;
```

We can already start working on our actions. This way, we will add the wrapper styles and its buttons.

```js
// @src/components/Modal.jsx

import React from "react";
import styles from "./Modal.module.css";
import { RiCloseLine } from "react-icons/ri";

const Modal = ({ setIsOpen }) => {
  return (
    <>
      <div className={styles.darkBG} onClick={() => setIsOpen(false)} />
      <div className={styles.centered}>
        <div className={styles.modal}>
          <div className={styles.modalHeader}>
            <h5 className={styles.heading}>Dialog</h5>
          </div>
          <button className={styles.closeBtn} onClick={() => setIsOpen(false)}>
            <RiCloseLine style={{ marginBottom: "-3px" }} />
          </button>
          <div className={styles.modalContent}>
            Are you sure you want to delete the item?
          </div>
          <div className={styles.modalActions}>
            <div className={styles.actionsContainer}>
              <button className={styles.deleteBtn} onClick={() => setIsOpen(false)}>
                Delete
              </button>
              <button
                className={styles.cancelBtn}
                onClick={() => setIsOpen(false)}
              >
                Cancel
              </button>
            </div>
          </div>
        </div>
      </div>
    </>
  );
};

export default Modal;
```

Now with our modal component finished just add it to our `App.jsx` but first let's create the following styles to have a more handy button on our page:

```css
/* @src/App.module.css */

.primaryBtn {
  margin: 20px 10px;
  cursor: pointer;
  font-weight: 500;
  padding: 13px 25px;
  border-radius: 15px;
  font-size: 0.8rem;
  border: none;
  color: white;
  background: #185adb;
  transition: all 0.25s ease;
}

.primaryBtn:hover {
  transform: translateY(-5px);
  box-shadow: 0 10px 20px -10px rgba(24, 90, 219, 0.6);
}
```

Now we can start working on our `App.jsx`. First we're going to import the `useState()` and we're going to create a state called isOpen and the setIsOpen function.

```js
// @src/App.jsx

import React, { useState } from "react";
import styles from "./App.module.css";

const App = () => {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <main>
      <button className={styles.primaryBtn} onClick={() => setIsOpen(true)}>
        Open Modal
      </button>
      // ...
    </main>
  );
};

export default App;
```

Then we just do conditional rendering to show the modal only when the isOpen state is true. In the same way we will pass the `setIsOpen()` function as a prop.


```js
// @src/App.jsx

import React, { useState } from "react";
import styles from "./App.module.css";

import Modal from "./components/Modal";

const App = () => {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <main>
      <button className={styles.primaryBtn} onClick={() => setIsOpen(true)}>
        Open Modal
      </button>
      {isOpen && <Modal setIsOpen={setIsOpen} />}
    </main>
  );
};

export default App;
```

You should get a result similar to this:

![final app](https://res.cloudinary.com/dj5iihhqv/image/upload/v1629543891/Kapture_2021-08-21_at_12.02.37-min_e1gtls.gif)

## Conclusion

As always, I hope you found it interesting. If you noticed any errors in this article, please mention them in the comments. 🤩

Hope you have a great day! 🪗 🙌