Open In App
Related Articles

Animated expanding card using framer-motion and ReactJS

Improve Article
Improve
Save Article
Save
Like Article
Like

In this article, we are going to learn how to create an animated expanding card using react and framer.

Prerequisites:

  1. Knowledge of JavaScript (ES6).

    JavaScript inbuilt methods we are going to make use are :

    1. Arrow function (ES6)
    2. Ternary operator
    3. Objects in JavaScript
  2. Knowledge of HTML/CSS.
  3. Basic knowledge of ReactJS

React hooks used in building this application are:

  1. React useState

Framer: components and hooks we are going to make use of in this tutorial are :

  1. https://www.framer.com/api/frame/
  2. https://www.framer.com/api/scroll/
  3. https://www.framer.com/api/utilities/#useanimation

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 animated-card
  • Step 2: After creating your project folder i.e. animated-card, move to it using the following command.

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

    $ npm install framer react-icons
    // For yarn
    $ yarn add framer react-icons

Open the src folder and delete the following files :

  1. logo.svg
  2. serviceWorker.js
  3. setupTests.js
  4. App.css
  5. App.js
  6. App.test.js (if any)

Create a file named Card.js.

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

Project structure

Example: 

index.js




import React from "react";
import { Frame, Scroll } from "framer";
import Card from "./Card";
import ReactDOM from "react-dom";
  
import "./index.css";
  
// main App HOC
export const App = () => {
  return (
    <Frame height={"100%"} width={"100%"} background={"#333"}>
      <Frame width={375} height={"100%"} background={"#FFF"} center>
        <Scroll width={375} height={"100%"}>
          {/* Card component with props yPos,title,subtitle */}
          <Card
            yPos={48}
            title={"GEEKSFORGEEKS"}
            subtitle="Don't learn alone"
          />
          <Card
            yPos={48 + 300 + 24}
            title={"reactJS"}
            subtitle="Most starred JavaScript library"
          />
        </Scroll>
      </Frame>
    </Frame>
  );
};
  
const rootElement = document.getElementById("root");
ReactDOM.render(<App />, rootElement);


index.css




body {
  margin: 0;
  cursor: pointer;
}


Card.js




import React, { useState } from "react";
import { ImCross } from "react-icons/im";
import { Frame, Scroll, useAnimation } from "framer";
  
// Card component with destructured props :
// yPos, title, subtitle
const Card = ({ yPos, title, subtitle }) => {
  
  // useState hook to manage the state of
  // expanding of card
  const [state, setState] = useState(false);
  
  // utility function to handle
  // onTap on card component
  const handleTap = () => {
    state ? controls.start({ y: 0 }) : setState(!state);
  };
  
  const controls = useAnimation();
  
  // Variants allow you to define animation
  // states and organise them by name.
  // They allow you to control animations 
  // throughout a component
  // tree by switching a single animate prop.
  const variants = {
    active: {
      width: 320,
      height: 800,
      borderRadius: 0,
      overflow: "visible",
      left: 28,
      right:0,
      y: 0,
      transition: { duration: 0.125, 
                    type: "spring"
                    damping: 10, 
                    mass: 0.6 }
    },
    inactive: {
      width: 280,
      height: 280,
      borderRadius: 24,
      overflow: "hidden",
      left: 45,
      y: yPos,
      transition: { duration: 0.125, 
                    type: "spring"
                    damping: 10,
                    mass: 0.6 }
    }
  };
  
  return (
    // basic container for layout, styling,
    // animation and events.
    <Frame
      y={yPos}
      variants={variants}
      animate={state ? "active" : "inactive"}
      width={300}
      height={300}
      borderRadius={24}
      style={state ? { zIndex: 10 } : { zIndex: 1 }}
      left={37.5}
      onTap={handleTap}
      shadow={
        state
          ? "0 0 0 0 rgba(0, 0, 0, 0)"
          : "0px 0px 20px 0px rgba(0, 0, 0, .25)"
      }
    >
      <Scroll
        width="100%"
        height="100%"
        backgroundColor={null}
        scrollAnimate={controls}
      >
        <Frame
          position="relative"
          backgroundColor={"#09a960"}
          width="100%"
          height={300}
        />
        <Frame position="relative" 
               height={1200} 
               background="white" />
  
        <Frame
          top={20}
          left={20}
          height={""}
          width={""}
          background={null}
          style={{
            color: "white",
            fontFamily: "sans-serif"
          }}
        >
          <span style={{ fontSize: "1.6em"
                         fontWeight: 600 }}>
                        {title}
          </span>
          <br />
          <span
            style={{
              fontSize: "1em",
              fontWeight: 500,
              opacity: 0.5
            }}
          >
            {subtitle}
          </span>
        </Frame>
      </Scroll>
      {state && (
        <Frame
          borderRadius={20}
          size={15}
          top={15}
          right={20}
          backgroundColor={"#09a960"}
          onTap={() => {
            setState(false);
          }}
        >
          <ImCross color="red" />
        </Frame>
      )}
    </Frame>
  );
};
  
export default Card;


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:


Whether you're preparing for your first job interview or aiming to upskill in this ever-evolving tech landscape, GeeksforGeeks Courses are your key to success. We provide top-quality content at affordable prices, all geared towards accelerating your growth in a time-bound manner. Join the millions we've already empowered, and we're here to do the same for you. Don't miss out - check it out now!

Last Updated : 17 Jan, 2022
Like Article
Save Article
Previous
Next
Similar Reads
Complete Tutorials