Open In App

Animated expanding card using framer-motion and ReactJS

Last Updated : 17 Jan, 2022
Improve
Improve
Like Article
Like
Save
Share
Report

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:



Like Article
Suggest improvement
Share your thoughts in the comments

Similar Reads