How I built an animated reusable React modal. 
Tags: react, modal, framermotion, styledcomponents
Published: 2020-06-03 14:13:53

---
title: How I built an animated reusable React modal. 
published: true
description: Today ill  walk you through the steps of how i built an animated modal using Framer motion and styled components. 
tags: react ,Modal ,framer motion,styled components
//cover_image: https://dev-to-uploads.s3.amazonaws.com/i/qw2xdh105vu3gfvmbrbx.png
---
Every web developer at some point of his/her career had to create a modal to display important dialogs to users,it might sound like a challenging task, the good news is it's not as difficult as it might seem to be :ok_woman: ,today I will walk you through how to build an animated modal using Framer motion and styled-components.

![demo](https://dev-to-uploads.s3.amazonaws.com/i/cfk00uy7i42d47ioa92v.gif)


Prerequisites
``` 
- Basic understanding of react components.
```
<br/>

###lets start by describing  the anatomy of a modal.

![Alt Text](https://dev-to-uploads.s3.amazonaws.com/i/qw2xdh105vu3gfvmbrbx.png)
An **Overlay** is basically a layer over the app it takes full width and height of the window and it stops all interactions with the app .
**Modal container** is a container that  encloses the content.
**Close button** button that would dismiss the modal.
**content** is what you actually want to show inside the modal.
<br/>
Now that we defined the structure of the modal lets create  our **Modal.js** file and install **styled-components** package.
at this point you might be wondering what is this famous styled-components 

  >Styled components is a CSS-in-JS styling framework that uses tagged template literals in JavaScript and the awesome power of CSS to provide a platform that allows you to write actual CSS to style react components.


now that styled-components is installed lets import the required libraries and define the component structure and style.
```javascript
import React from 'react'
import styled from 'styled-components'

const Overlay=styled.div`
position:fixed;
    top:0;
    left:0;
    width:100%;
    height:100%;
    background:rgba(0,0,0,0.3);
`
const ModalContainer = styled.div`
    width:50%;
    height:50%;
    background-color: white;
    position:absolute;               // ----.
    top:50%;                         //     |positioning the container
    left:50%;                        //     |in the middle
    transform:translate(-50%,-50%);  //  ----.
border-radius:12px`

const CloseButton = styled.svg`
    width:20px;
    height:20px;
    position: absolute;
    right:18px;
    top:18px;
    cursor:pointer;
`


const Modal = ({ handleClose, children, isOpen }) => {
  if (isOpen) {
    return (
      <Overlay>
        <ModalContainer>
          <CloseButton
            onClick={handleClose}
            xmlns="http://www.w3.org/2000/svg"
            viewBox="0 0 20.39 20.39"
          >
            <title>close</title>
            <line
              x1="19.39"
              y1="19.39"
              x2="1"
              y2="1"
              fill="none"
              stroke="#5c3aff"
              strokeLinecap="round"
              strokeMiterlimit="10"
              strokeWidth="2"
            />
            <line
              x1="1"
              y1="19.39"
              x2="19.39"
              y2="1"
              fill="none"
              stroke="#5c3aff"
              strokeLinecap="round"
              strokeMiterlimit="10"
              strokeWidth="2"
            />
          </CloseButton>
          {children}
        </ModalContainer>
      </Overlay>
    );
  } else {
    return <></>;
  }
};

export default Modal
 ```
Thanks to the styled components we created our structure with CSS inside the JS file, notice that we have isOpen prop to show and hide the modal and handle close to to dismiss the modal. 

Time to dive into [**Framer motion**](https://www.framer.com/api/motion/#quick-start) and create an animated button to open the modal 
create an other file name it **OpenModalButton.js**
```javascript
import React from "react";
import { motion } from "framer-motion";
import styled from "styled-components";

const OpenModalButton = styled(motion.button)`
  font-size: 1.2rem;
  padding: 20px;
  border-radius: 50px;
  border: none;
  background-color: #5c3aff;
  color: white;
`;
const animatedOpenButton = ({ children }) => {
  return (
    <OpenModalButton whileHover={{ scale: 1.1 }} whileTap={{ scale: 0.9 }}>
      {children}
    </OpenModalButton>
  );
};

export default animatedOpenButton;



```

I will be importing both components in App.js for demonstration purpose and define event  handelers.

```javascript
import React, { useState } from "react";
import "./styles.css";
import Modal from "./Modal";
import OpenModalButton from "./OpenModalButton";

export default function App() {
  const [isOpen, toggle] = useState(false);

  function handlOpenModal(open) {
    console.log("close modal");
    toggle(open);
  }

  return (
    <div className="App">
      <OpenModalButton handlClick={() => handlOpenModal(true)}>
        Open modal
      </OpenModalButton>
      <Modal isOpen={isOpen} handleClose={() => handlOpenModal(false)} />
    </div>
  );
}
```
#Here comes the fun part .... **Animation!!!!** :grinning:#
to do that we need to migrate some of the modal components to framer motion components.
lets start with the **Overlay** we want it to transition from:
                
       initial state          open                upon exit
       opacity :0 ===========> opacity :1;=======>opacity:0 
```javascript 
import {motion,AnimatePresence} from 'framer-motion'

const Overlay = styled(motion.div)`
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: rgba(0, 0, 0, 0.3);
  cursor: pointer;
`;
const Modal = ({ handleClose, children, isOpen }) => {
  return(
  <AnimatePresence>
      {isOpen &&
      <Overlay initial={{opacity:0}} animate={{opacity:1}} exit={{opacity:0}}>
     /*.....*/
      </Overlay>
      }
  </AnimatePresence>
  
    );
  
};

export default Modal;
```
I wrapped the modal inside [AnimatePresence](https://www.framer.com/api/motion/animate-presence/) which helps animate a component before being removed  using exit attribute.
Time to orchestrate the overlay animation with the container using [variants](https://www.framer.com/api/motion/animation/#variants)
we will animate the container from :
top :'-50%' to top:'50%'
with transition type spring to give it a bouncy feel to it.
lets declare our variants:

```javascript
/*...*/

const modalVariant = {
  initial: { opacity: 0 },
  isOpen: { opacity: 1 },
  exit: { opacity: 0 }
};
const containerVariant = {
  initial: { top: "-50%", transition: { type: "spring" } },
  isOpen: { top: "50%" },
  exit: { top: "-50%" }
};
const Modal = ({ handleClose, children, isOpen }) => {
  return (
    <AnimatePresence>
      {isOpen && (
        <Overlay
          initial={"initial"}
          animate={"isOpen"}
          exit={"exit"}
          variants={modalVariant}
        >
          <ModalContainer variants={containerVariant}>
            /*...*/
          </ModalContainer>
        </Overlay>
      )}
    </AnimatePresence>
  );
};

export default Modal;
```

we are finally done you can check the code source.


[![Edit react animated modal.](https://codesandbox.io/static/img/play-codesandbox.svg)](https://codesandbox.io/s/react-animated-modal-9rm6l?fontsize=14&hidenavigation=1&theme=dark)