Skip to content
Related Articles

Related Articles

Improve Article

Animated shared layout using framer-motion and React.js

  • Last Updated : 12 Mar, 2021

The following approach covers how to create an animated shared layout using framer-motion and ReactJS.

Prerequisites:

  1. Knowledge of JavaScript (ES6)
  2. Knowledge of HTML/CSS.
  3. Basic knowledge of ReactJS.

Creating React Application And Installing Module:

  • Step 1: Create a React application using the following command:

    npx create-react-app animated-layout
  • Step 2: After creating your project folder i.e. animated-layout, move to it using the following command.



    cd animated-layout
  • Step 3: Add the npm packages you will need during the project :

    npm install framer-motion

Now open the src folder and delete the following files and create a JavaScript file named Item.js.

  • logo.svg
  • serviceWorker.js
  • setupTests.js
  • App.test.js (if any)
  • index.css

Project Structure: Your project structure tree should look like this:

Folder structure

Example:

  • We are going to create an Item component that is the animated layout using react useState hook and framer-motion components motion and AnimatePresence.
  • Content component is used to create Item’s (animated shared layout) content using HTML img tag and div & framer-motion component motion.
  • The toggleOpen is a utility function to set the ‘isOpen’ value not (!) of its last value.
  • In App.js, itemList is for the number of animated shared layout we want to create, in our case it is 3.
  • In App.js, we are going to use framer-motion AnimatedSharedLayout component to wrap the imported Item component and map through ‘itemsList’ array to render animated layouts.

App.js




import React from "react";
import { AnimateSharedLayout } from "framer-motion";
import Item from "./Item";
import "./styles.css";
  
// This is an example of animating shared layouts 
// using react and framer-motion library.
const itemsList = [
  {
    index: 0,
    content: `Motion components are DOM primitives 
  optimised for 60fps animation and gestures.`
  },
  {
    index: 1,
    content: `Motion can animate:
    Numbers: 0, 10 etc.
    Strings containing numbers: "0vh", "10px" etc.`
  },
  {
    index: 2,
    content: `Transform properties are accelerated by the GPU,
     and therefore animate smoothly. `
  }
];
  
const App = () => {
  return (
    // The framer-motion component to wrap Item component to animate it 
    <AnimateSharedLayout>
      {/* Mapping through itemList array to render layouts*/}
      {itemsList.map((item) => (
        <Item key={item.index} content={item.content} />
      ))}
    </AnimateSharedLayout>
  );
};
  
export default App;

Item.js




import React, { useState } from "react";
import { motion, AnimatePresence } from "framer-motion";
  
const Content = ({ content }) => {
  
    "20200817185016/gfg_complete_logo_2x-min.png"
  
  return (
    <motion.div
      layout
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    >
      <img
        src={url}
        alt="geeksforgeeks"
      />
      <div className="row">{content}</div>
    </motion.div>
  );
};
  
const Item = ({ content }) => {
  // React useState hook is used to manage the state of 'isOpen'
  // that in turn toggles shared layout, user clicks on
  const [isOpen, setIsOpen] = useState(false);
  
  // Utility function to set 'isOpen' '!'(not) of its last value
  const toggleOpen = () => setIsOpen(!isOpen);
  
    "27UlohMeBLxyUdhs9hUbc-Agw=s900-c-k-c0x00ffffff-no-rj"
  
  return (
    <motion.li
      layout
      title="Click to reveal"
      onClick={toggleOpen}
      initial={{ borderRadius: [25] }}
    >
      <motion.div className="avatar" layout>
        {" "}
        <img
          src={url}
          alt="gfg"
        />{" "}
      </motion.div>
      <br />
      <AnimatePresence>{isOpen && <Content content={content} />}
      </AnimatePresence>
    </motion.li>
  );
};
  
export default Item;

styles.css




body {
  min-height: 100vh;
  margin: 0;
  display: flex;
  justify-content: center;
  align-items: center;
}
  
* {
  box-sizing: border-box;
}
  
ul,
li {
  list-style: none;
  margin: 0;
  padding: 0;
}
  
ul {
  width: 300px;
  display: flex;
  flex-direction: column;
  background: #fcfcfc;
  padding: 20px;
  border-radius: 25px;
}
  
li {
  background-color: rgba(214, 214, 214, 0.5);
  border-radius: 10px;
  padding: 20px;
  margin-bottom: 20px;
  overflow: hidden;
  cursor: pointer;
  width: 300px;
}
  
li:last-child {
  margin-bottom: 0px;
}
  
.avatar {
  width: 40px;
  height: 40px;
  border-radius: 20px;
}
  
.avatar img {
  width: 40px;
  border-radius: 100%;
}
  
.row {
  margin-top: 12px;
}
  
img {
  width: 250px;
  height: 40px;
}

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:




My Personal Notes arrow_drop_up
Recommended Articles
Page :