In this article, we are going to learn how to create an animated modal using react, framer-motion & styled-components.
Prerequisites:
- Knowledge of JavaScript (ES6).
- Knowledge of HTML/CSS.
- Basic knowledge of ReactJS.
Framer-motion: The components and attributes we are going to make use of in this tutorial.
- https://www.framer.com/api/motion/component/
- https://www.framer.com/api/motion/animate-presence/
Creating React Application And Installing Module :
Step 1: Now, you will start a new project using create-react-app so open your terminal and type.
npx create-react-app toggle-modal
Step 2: After creating your project folder i.e. toggle-modal, move to it using the following command.
cd toggle-modal
Step 3: Add the npm packages you will need during the project.
npm install framer-motion styled-components //For yarn yarn add framer-motion styled-components
Step 5: Now open your newly created project with your favorite code editor, I am using Visual Studio Code and will recommend you to use the same.
Open the src folder and delete the following files:
- logo.svg
- serviceWorker.js
- setupTests.js
- index.css
- App.test.js (if any)
Create a file named Styles.js.
Project structure: Your folder structure tree should look like this.
Project structure
Approach:
- We are going to create a Modal component with ‘showModal’ prop only to manage its state of visibility and animated using framer-motion AnimatePresence.
- AnimatePresence allows components to animate out when they’re removed from the React tree and to enable exit animations.
- To give spring animation to modal container we will use framer-motion spring animation with stiffness = 300.
- Content of modal is neveropen image which is also animated using framer-motion motion.div.
- React useState hook to manage the state of ‘showModal’ i.e. responsible to toggle the modal container.
- ‘displayModal’ utility function to set the ‘showModal’ value opposite of its last value to toggle modal.
- Event listener for document body so that on clicking outside or on the modal, ‘showModal’ is set to false and in turn modal is disappeared.
- ToggleBtn is also animated using framer-motion motion.button.
Example:
Styles.js
import styled from "styled-components"; import { motion } from "framer-motion"; Â Â export const ModalBox = styled(motion.div)` Â Â position: relative; Â Â z-index: 2; Â Â width: 400px; Â Â height: 200px; Â Â display: flex; Â Â justify-content: center; Â Â align-items: center; Â Â background: #fff; `; Â Â export const ModalContent = styled(motion.div)` Â Â padding: 5px; `; Â Â export const ModalContainer = styled.div` Â Â height: 100vh; Â Â background: #111; Â Â display: flex; Â Â flex-direction: column; Â Â align-items: center; `; Â Â export const ToggleBtn = styled(motion.button)` Â Â cursor: pointer; Â Â font-size: 20px; Â Â color: #fff; Â Â padding: 0.5rem 0.8rem; Â Â margin-top: 3rem; Â Â background: #3bb75e; Â Â text-decoration: none; Â Â border: none; Â Â border-radius: 50px; `; |
App.js
import React, { useState } from "react"; import { AnimatePresence } from "framer-motion"; import { ToggleBtn, ModalBox, ModalContent, ModalContainer } from "./Styles"; import "./App.css";   // Modal component with 'showModal' prop only // to manage its state of visibility and // animated using framer-motion const Modal = ({ showModal }) => {   return (     <ModalContainer>       <AnimatePresence>         {showModal && (           <ModalBox             initial={{ opacity: 0,                        y: 60, scale: 0.5 }}             animate={{               opacity: 1,               y: 0,               scale: 1,               // making use of framer-motion spring animation               // with stiffness = 300               transition: { type: "spring",                             stiffness: 300 }             }}             exit={{ opacity: 0, scale: 0.5,                     transition: { duration: 0.6 } }}>             <ModalContent               initial={{ y: -30, opacity: 0 }}               animate={{ y: 0, opacity: 1,                          transition: { delay: 0.5 } }}>               {/* Modal content is neveropen image */}               <img                 src="Modal image link"                alt="neveropen"              />             </ModalContent>           </ModalBox>         )}       </AnimatePresence>     </ModalContainer>   ); };   const App = () => {   // React useState hook to manage the state of 'showModal'   // i.e. responsible to toggle the modal container   const [showModal, setShowModal] = useState(false);     // utility function to set the showModal value   // opposite of its last value   // to toggle modal   const displayModal = () => {     setShowModal(!showModal);     document.getElementById("btn").style.visibility = "hidden";   };     // event listener for document body   // so that on clicking outside the modal,   // 'showModal' is set to false.   document.body.addEventListener("click", () => {     if (showModal) {       setShowModal(false);     }   });     return (     <ModalContainer>       <ToggleBtn         id="btn"        initial={{ x: -700 }}         animate={{           x: 0,           transition: { duration: 0.1 }         }}         // event listener for the toggle button         // to display modal on click         onClick={displayModal}>         Toggle Modal       </ToggleBtn>       {/* passing 'showModal' as a prop to Modal component */}       <Modal showModal={showModal} />     </ModalContainer>   ); };   export default App; |
index.js
import React from "react"; import ReactDOM from "react-dom"; import App from "./App"; Â Â ReactDOM.render( Â Â <React.StrictMode> Â Â Â Â <App /> Â Â </React.StrictMode>, Â Â document.getElementById("root") ); |
App.css
* { Â Â margin: 0; Â Â box-sizing: border-box; } Â Â img { Â Â padding: 5px; Â Â width: 400px; Â Â overflow: hidden; } |
Step to Run Application: Run the application using the following command from the root directory of the project.
npm start
Output: Now open your browser and go to http://localhost:3000/, you will see the following output.
