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.
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.