Animated Modal in React
Tags: modal, css, webdev, react
Published: 2022-09-11 18:30:41

This will be a guide to setting up a modal that will pop in the center of the screen.

## Create a Modal Component

```jsx
import React from "react"

function Modal(props) {
  return (
    <div className="modal">
      <div className="modal-content">
        <div className="modal-header">
          <h4 className="modal-title">Modal Title</h4>
        </div>
        <div className="modal-body">Modal Body</div>
        <div className="modal-footer">
          <button className="button">Close</button>
        </div>
      </div>
    </div>
  )
};

export default Modal
```

### Style the Modal


```css
/* Modal */

.modal {
  position: fixed;
  left: 0;
  top: 0;
  right: 0;
  bottom: 0;
  background-color: rgba(0, 0, 0, 0.5);
  display: flex;
  align-items: center;
  justify-content: center;
}

.modal-content {
  width: 500px;
  background-color: #fff;
}

.modal-header, .modal-footer {
  padding: 10px;
}

.modal-body {
  padding: 10px;
  border-top: 1px solid #eee;
  border-bottom: 1px solid #eee;
}
```

## Import to App.js

```jsx
import React from "react"
import Modal from "./components/Modal/Modal"

function App() {
  return (
    <div className="App">
      <button >Show Modal</button>
      <Modal />
    </div>
  )
}
```

## Show the modal

When the `Show Modal` button is pressed the modal should pop up.

Using state will allow the modal to show or be hidden depending on the current state. In `Modal.js`, add the following prop check for if the modal should be shown.

```jsx
// Modal.js

function Modal(props) {
  if (!props.show) {
    return null
  }

...

}
```

Using `useState` add a state object to `App.js`:

```jsx
import React, { useState } from "react"
import Modal from "./components/Modal/Modal.jsx"
import "./App.css"

function App() {
  const [show, setShow] = useState(false)
  return (
    <div className="App">
      <h1>Scratch Pad</h1>
      <button onClick={() => setShow(true)}>Show Modal</button>
      <Modal show={show}/>
    </div>
  )
}

export default App
```

## Hide the modal

Update the following code to implement a way to close the modal without the need for a function by changing `state` props.

```jsx
// App.js

<button onClick={() => setShow(true)}>Show Modal</button>
<Modal onClose={() => setShow(false)} show={show} />
```

```jsx
// Modal.js

<div className="modal-footer">
  <button onClick={props.onClose} classname="button">Close</button>
</div>
```

### Close modal on outside click

We should add a way for the modal to close on its own when clicked off the modal.

Functionality will remain as expected, ability to click content on the modal without closing, and be able to close by clicking the `close` button or off the modal.

```jsx
// Modal.js

return (
  <div className="modal" onClick={props.onClose}>
    <div className="modal-content" 
         onClick={(e) => e.stopPropagation()}>
      ...
    </div>
  </div>
)
```

The modal should close when clicked outside of the modal content box, but do nothing when clicked inside.

Now to give it a drop-in animation

## Animate the modal

Add in the following to give the modal a drop down animation when it has been opened.

```css
.modal {
  ...
  opacity: 0;
  transition: all 0.3s ease-in-out;
  pointer-events: none;
}

.modal.show {
  opacity: 1;
  pointer-events: visible;
}

.modal-content {
  ...
  transform: translateY(-200px);
  transition: all 0.3s ease-in-out;
}

.modal-show .modal-content {
  transform: translateY(0);
}
```

And finally using `useState` hook handle the `.show` class.

```jsx
// Modal.js

function Modal(props) {
  // if (!props.show) { return null } should be removed.
  return (
    <div className={`modal ${props.show ? "show" : ""}`} onClick={props.onClose}>
    ...
    </div>
  )
}
```

The `null` check should be removed since the show/hide functionality is being handled through CSS now.

And now you have a modal with a slight animation. Play with the transition/transform settings to make it behave in the manner that you wish.





[back to top](#create-a-modal-component)