Type to generate custom UI components with AI

Type to generate UI components from text

OR

Browse thousands of MUI, Tailwind, React components that are fully customizable and responsive.

Explore Components

How to Add Animations to a React App with Framer Motion

Framer Motion is a popular production-ready motion library for React that makes it easy to add smooth, engaging animations to React applications.

This article explores the key capabilities of Framer Motion and demonstrates how to leverage its declarative API, pre-built components, and robust feature set to implement performant animations that enhance your React apps’ interactivity, visual feedback, and user experience.

Through this article, you will learn about the importance of adding animations to your application, I will walk you through the fundamentals of Framer Motion, best practices for animation implementation, and techniques for advanced capabilities like variant coordination, page transitions, drag-and-drop behaviors, SVG animation, and optimization.

Overview of Framer Motion as a React Animation Library

Framer Motion

Framer Motion is a poduction-ready motion library for React, it an open-source motion library that is React-based animation library that makes it simple to implement sophisticated animations and interactions in web applications. Maintained by the Framer design team, Framer Motion offers a declarative API for adding animations with minimal code through the flexible motion component.

The motion component can be used to animate the properties of any HTML or SVG element, React component, providing props like animate, initial, transition, and drag to describe animations. For example, you can animate the x-position of a div with just a couple of lines of code. Framer Motion also includes features like the AnimatePresence component for animating components as they mount and unmount, user interaction animations through whileHover, whileTap, and onDrag props, and easy manipulation of SVG properties like pathLength and fill to animate vectors.

Additional capabilities provided by Framer Motion include gesture recognition, drag-and-drop animation, responsive variant animations, and the ability to orchestrate sequencing and staggering of animation timelines. Framer also offers excellent documentation and guides for tackling more advanced configurations.

Are you searching for ways to enhance your team’s productivity? Explore Purecode AI, an AI custom component generator that covers everything from HTML and CSS to Tailwind, JavaScript, and more.

Purecode AI homepage

Why Framer Motion for React Animations?

There are several reasons why Framer Motion is a great choice for creating animations in React, such as:

  • Popularity and active maintenance: Framer Motion is a fairly popular and actively maintained library, with over 20k stars on GitHub, and plenty of resources to support it. It is also used by many well-known companies and products, such as Netflix, Spotify, Airbnb, and Dropbox.

  • Focus on complex animations with minimal code: Framer Motion is designed to make complex animations easy and intuitive, without requiring a lot of code or configuration. You can use simple props to animate any HTML or SVG element, and leverage features like variants, orchestration, and layout animations to create coordinated and responsive animations.

  • Advantages of using Framer Motion for tasks like drag-and-drop and SVG animations: Framer Motion also offers some unique advantages for specific tasks that are otherwise difficult or tedious to implement with other libraries or methods. For example, Framer Motion makes it very simple to add drag-and-drop functionality to any element with the drag prop and customize the drag constraints and elasticity with additional props. Similarly, Framer Motion allows you to animate SVG elements by manipulating properties like pathLength, strokeDashoffset, and fill, without having to use complex CSS animations or external libraries.

Check out this explainer YouTube video on Animating React Apps with Framer Motion:

Framer Motion Components and APIs

Framer Motion offers a simple but comprehensive API for creating animations in your applications. The library is built around two core components: motion and AnimatePresence.

Motion Component

You can animate common HTML or SVG elements with the motion component. Replace any HTML or SVG tag with this component, and it will have all the animation capabilities that Framer Motion offers.

Animating a motion component is as straightforward as setting values on the animate prop. The animate prop can accept an object of values. When one of them changes, the motion component will automatically animate to the new state. The animation used can be configured using the transition prop.

Here’s an example of how you can use the motion component to animate a div:

import { motion } from 'framer-motion';

const MyComponent = () => (
  <motion.div
    initial={{ opacity: 0 }}
    animate={{ opacity: 1 }}
    transition={{ duration: 1 }}
  >
    Hello, world!
  </motion.div>
);

AnimatePresence Component

The AnimatePresence component allows you to animate components as they mount and unmount, providing a way to control exit animations. This is particularly useful for animating modal windows, pages, or any other components that enter and leave the DOM.

Here is an example of how you can use AnimatePresence to animate a modal window:

import { motion, AnimatePresence } from 'framer-motion';

const Modal = ({ isOpen }) => (
  <AnimatePresence>
    {isOpen && (
      <motion.div
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
        transition={{ duration: 0.2 }}
      >
        This is a modal window.
      </motion.div>
    )}
  </AnimatePresence>
);

Transition Prop

You can adjust the length, delay, kind of interpolation, and other features of your animations with the transition prop. For example, you can create an ease-in-out transition that lasts 0.5 seconds like this:

<motion.div
  animate={{ scale: 1.5 }}
  transition={{ duration: 0.5, ease: "easeInOut" }}
/>

Gestures

Framer Motion supports gesture animations out of the box. This means you can easily add animations that respond to user interactions like hovering, tapping, or dragging. For instance, you can create a button that scales up when hovered over like this:

<motion.button whileHover={{ scale: 1.1 }}>Hover over me</motion.button>

Implementing Animations in a React App using Framer Motion

Implementing animations in a React app using Framer Motion involves a few key steps. Let’s walk through them using a simple example: a notification tray that animates into view when a button is clicked.

Project Setup And Starter Code

Begin by navigating to the directory where you want the example to reside. Next, open your terminal and create a starter React app using Vite with the following command:

npm create vite@latest

Then, answer to the prompts like this:

React Project Setup With Vite

Install and Run the Application

Now, cd into your newly created project, run npm install, and then npm run dev. The project folder should now look like this:

Framer Project Folder

Delete the src/assets directory and App.css file. Now, write the code for the navigation tray with no animation. Begin with the project’s CSS and replace the contents of index.css with the following:

:root {
  font-family: Inter, system-ui, Avenir, Helvetica, Arial, sans-serif;
  font-weight: 400;
}

body {
  margin: 0;
  min-width: 320px;
  min-height: 100vh;
  background-color: #fff;
  color: #111827;
}

header {
  height: 4rem;
  font-size: 1.1rem;
  border-bottom: 1px solid #e5e7eb;
  display: flex;
  align-items: center;
  padding: 0 2rem;
}

header > .header__left {
  width: 50%;
  font-size: 1.5rem;
}

header > .header__right {
  width: 50%;
  display: flex;
  justify-content: flex-end;
  align-items: center;
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.header__right > * {
  margin: 01.5rem;
  position: relative;
}

.header__right > .notification__button {
  height: 2rem;
  width: 2rem;
  cursor: pointer;
}

.header__right > .notification__icon {
  height: 100%;
  width: 100%;
}

.header__right > .image {
  border-radius: 50%;
  height: 3rem;
  width: 3rem;
  overflow: hidden;
}

.header__right > .image > img {
  height: 100%;
  width: 100%;
}

.notification__tray {
  border-radius: 6px;
  box-shadow: 0px 0px 8px #e5e7eb;
  position: fixed;
  width: 24rem;
  top: 4.5rem;
  right: 2rem;
  color: rgb(65, 65, 81);
  font-size: 0.875rem;
  line-height: 1.25rem;
}

.notification__tray > ul {
  list-style-type: none;
  margin: 0;
  padding: 0;
}

.notification__tray li {
  padding: 1rem 2rem;
  border-bottom: 1px solid #e5e7eb;
  display: flex;
  align-items: center;
  justify-content: space-between;
}

.notification__tray li:hover {
  background-color: #e5e7eb;
  color: #111827;
}

.notification__tray li .clear__button {
  width: 1.5rem;
  height: 1.5rem;
  cursor: pointer;
}

.notification__tray li .clear__icon {
  width: 100%;
  height: 100%;
}

.todo__header {
  text-align: center;
}

.todo__container {
  list-style-type: none;
}

.todo__item {
  border: 1px solid #e5e7eb;
  border-radius: 5px;
  box-shadow: 0px 0px 8px #e5e7eb;
  color: #111827;
  margin: 1.5 rem auto;
  width: 50px;
  padding: 1.5rem2rem;
  background-color: #e5e7eb;
}

The page header code comes next. In src, make a file called Header.jsx and fill it with this:

import { useState } from "react";
import NotificationTray from "./NotificationTray";

const initialNotifications = [
  "User #20 left you a like!",
  "User #45 sent you a friend request",
  "Your song has been uploaded!",
  "Thanks for signing up!",
];

const Header = () => {
  const [showNotifications, setShowNotifications] = useState(false);
  const [notificationContent, setNotificationContent] =
    useState(initialNotifications);

  const handleDeleteNotification = (content) => {
    setNotificationContent(
      notificationContent.filter((item) => item !== content)
    );
  };

  return (
    <header>
      <div className="header__left">Brand</div>
      <ul className="header__right">
        <li
          className="notification__button"
          onClick={() => {
            setShowNotifications(!showNotifications);
          }}
        >
          <svg
            xmlns="<http://www.w3.org/2000/svg>"
            fill="none"
            viewBox="0 0 24 24"
            strokeWidth="1.5"
            stroke="currentColor"
            className="notification__icon"
          >
            <path
              strokeLinecap="round"
              strokeLinejoin="round"
              d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5"
            />
          </svg>
        </li>
        <li className="image">
          <img src="<https://www.dummyimage.com/48x48>" />
        </li>
      </ul>

      {showNotifications ? (
        <NotificationTray
          notificationContent={notificationContent}
          handleDeleteNotification={handleDeleteNotification}
        ></NotificationTray>
      ) : null}
    </header>
  );
};
export default Header;

For the sake of brevity, we will not go over the starter code in detail, but it does the following things:

  • Imports the notification tray component.

  • Creates a tray state and a helper function for removing notifications.

  • Creates the markup for the header and conditionally renders the tray.

Next, create code for the notification tray component. Create a file called NotificationTray.jsx and paste this code into it:

const NotificationTray = ({
  notificationContent,
  handleDeleteNotification,
}) => {
  return (
    <div className="notification__tray">
      <ul>
        {notificationContent.map((content) => {
          return (
            <li key={content}>
              <span>{content}</span>
              <span
                className="clear__button"
                onClick={() => {
                  handleDeleteNotification(content);
                }}
              >
                <svg
                  xmlns="<http://www.w3.org/2000/svg>"
                  fill="none"
                  viewBox="0 0 24 24"
                  strokeWidth={1.5}
                  stroke="currentColor"
                  className="clear__icon"
                  title="Clear notification"
                >
                  <path
                    strokeLinecap="round"
                    strokeLinejoin="round"
                    d="M9.75 9.75l4.5 4.5m0-4.5l-4.5 4.5M21 12a9 9 0 11-18 0 9 9 0 0118 0z"
                  />
                </svg>
              </span>
            </li>
          );
        })}
      </ul>
    </div>
  );
};
export default NotificationTray;

The code:

  • Displays tray status as a <ul> with <li> for each notification.

  • When the clear button is clicked, the helper function from Header.jsx is called to remove the notification.

Finally, render the header in App.jsx as follows:

import Header from "./Header"

function App() {
  return (
    <>
      <Header></Header>
    </>
  )
}
export default App

All of this covers the code required to get the notification tray to function properly. When you look at your React app in the browser, you should see a webpage like this:

Webpage With Working Notification Tray

Adding Animation with Framer Motion

We will begin animating a bell icon. The ringing motion that appears when hovering is generated by rotating the SVG icon along the z-axis in one direction and then the other, and then returning it to normal.

Import motion and AnimatePresence from Framer Motion

Here’s how: At the top of Header.jsx, import motion and AnimatePresence from Framer Motion.

import {motion, AnimatePresence} from "framer-motion";

Next, add animation to the SVG in Header.jsx:

<motion.svg
  whileHover={{
    rotateZ: [0, -20, 20, -20, 20, -20, 20, 0],
    transition: { duration: 0.5 },
  }}
  xmlns="http://www.w3.org/2000/svg"
  fill="none"
  viewBox="0 0 24 24"
  strokeWidth="1.5"
  stroke="currentColor"
  className="notification__icon"
>
  <path
    strokeLinecap="round"
    strokeLinejoin="round"
    d="M14.857 17.082a23.848 23.848 0 005.454-1.31A8.967 8.967 0 0118 9.75v-.7V9A6 6 0 006 9v.75a8.967 8.967 0 01-2.312 6.022c1.733.64 3.56 1.085 5.455 1.31m5.714 0a24.255 24.255 0 01-5.714 0m5.714 0a3 3 0 11-5.714 0M3.124 7.5A8.969 8.969 0 015.292 3m13.416 0a8.969 8.969 0 012.168 4.5"
  />
</motion.svg>

The SVG code now uses Framer Motion to add interactivity. Specifically:

  • The entire SVG is wrapped in a motion.svg component to enable animations

  • A whileHover prop is added so that the animation only occurs on hover

  • The whileHover prop passes an object with a rotate keyframe animation from 0 degrees to -10 degrees and back to 0 degrees on hover

  • This creates a smooth back-and-forth rocking animation of the SVG when hovered over

  • A transition property is set so the animation lasts 0.5 seconds, creating a smooth effect

After that, you should see the bell ring when you hover over it on your webpage.

Animated Bell Icon

Fade-In Animation

The next animation you’ll add is a fade-in on entry animation for the notification tray. In Notification.jsx, import motion and AnimatePresence:

import { motion, AnimatePresence } from "framer-motion";

Then modify the outermost div as follows:

<motion.div
  className="notification__tray"
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
>
  <ul>
    .....
  </ul>
</motion.div>

All that changed was that the div was renamed motion.div, and you changed the values of the initial and animate props so that the div begins with an opacity of 0 and animates to become fully visible. Repeat on the <li>s returned from the map and add 0.2 seconds as shown:

{
  notificationContent.map((content) => {
    return (
      <motion.li
        key={content}
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        transition={{ duration: 0.2 }}
      >
        ...
      </motion.li>
    )
  })
}

Let’s add an extra touch by animating each notification’s exit. This will be accomplished by adding a slide-away animation when a li is removed from the tray. Simply wrap the <li>s with an AnimatePresence component and use the exit prop to specify what happens when each <li> is removed. Let’s see how it works.

<ul>
  <AnimatePresence>
    {notificationContent.map((content) => {
      return (
        <motion.li
          key={content}
          initial={{ opacity: 0 }}
          animate={{ opacity: 1 }}
          exit={{ x: "-12rem", opacity: 0 }}
          transition={{ duration: 0.2 }}
          layout
        >
          ....
        </motion.li>
      )
    })}
  </AnimatePresence>
</ul>

The exit prop specifies that when the <li> is removed, it should move 12rem (half the width of the tray) to the left and fade away before being unmounted. The layout prop instructs Framer Motion to animate any changes in an element’s position caused by layout shifts. When a <li> is removed from the tray, its siblings glide into their new positions rather than jumping up to fill the space. Take a moment to check it out for yourself.

Your final task for this section is to animate the tray’s exit (when it disappears after clicking the bell). The desired animation is identical to the exit animation on the <li>s: slide left and fade away.

Go back to Header.jsx and wrap the NotificationTray component with AnimatePresence:

<AnimatePresence>
  {showNotifications ? (
    <NotificationTray
      notificationContent={notificationContent}
      handleDeleteNotification={handleDeleteNotification}
    ></NotificationTray>
  ) : null}
</AnimatePresence>

Then, within NotificationTray.jsx, add an exit prop to the outermost div.

<motion.div
  className="notification__tray"
  initial={{ opacity: 0 }}
  animate={{ opacity: 1 }}
  exit={{ opacity: 0, x: "-12rem" }}
>
  <ul>...</ul>
</motion.div>

And that concludes the fundamentals of our animations! Your tray should now display animations like this:

Working Animations In Our Notification Tray Using Framer Motion

Next, you’ll learn how to use variants to improve your code and orchestrate child animations.

Variants in Framer Motion

Variants in Framer Motion provide a way to predefined animation states and sequences, allowing for cleaner and more maintainable code. They are particularly useful when you have complex animations or when multiple elements share similar animations.

Introduction to Variants

A variant is an object that defines one or more animation states. You can define variants on a parent component and then use them in child components. With this, you can coordinate animations across multiple components.

Here’s an example of how to define and use variants:

import { motion } from 'framer-motion';

const containerVariants = {
  hidden: { opacity: 0 },
  visible: { opacity: 1 },
};

const itemVariants = {
  hidden: { x: -10, opacity: 0 },
  visible: { x: 0, opacity: 1 },
};

const MyComponent = () => (
  <motion.div variants={containerVariants} initial="hidden" animate="visible">
    <motion.div variants={itemVariants} />
    <motion.div variants={itemVariants} />
    <motion.div variants={itemVariants} />
  </motion.div>
);

Here, the containerVariants object defines two states: hidden and visible. These states are used by the container div. The itemVariants object defines the same two states for the child div elements.

Creating a Notification Tray Variant

Let’s apply variants to our notification tray example from the previous section. We will define a trayVariants object with open and closed states:

const trayVariants = {
  open: { y: '0%' },
  closed: { y: '-100%' },
};

Then, we will use these variants in our motion.div:

<motion.div
  variants={trayVariants}
  initial="closed"
  animate={isOpen ? 'open' : 'closed'}
  transition={{ duration: 0.3 }}
>
  This is the notification tray.
</motion.div>

Now, our code is cleaner and easier to understand. The animation states are clearly defined in one place, and we can easily add more states if needed.

Staggering Child Animations

One of the powerful features of variants is the ability to stagger animations of child components. For example, if our notification tray contained multiple items, we could animate them in sequence rather than all at once.

First, we will add some items to our tray:

<motion.div
  variants={trayVariants}
  initial="closed"
  animate={isOpen ? 'open' : 'closed'}
  transition={{ duration: 0.3 }}
>
  <motion.div variants={itemVariants}>Item 1</motion.div>
  <motion.div variants={itemVariants}>Item 2</motion.div>
  <motion.div variants={itemVariants}>Item 3</motion.div>
</motion.div>

Then, we will define an itemVariants object with open and closed states:

const itemVariants = {
  open: { opacity: 1, y: 0 },
  closed: { opacity: 0, y: -10 },
};

Finally, we will modify our open state in trayVariants to stagger the child animations:

const trayVariants = {
  open: { y: '0%', transition: { staggerChildren: 0.1 } },
  closed: { y: '-100%' },
};

Now, when the tray opens, the items will animate into view one after the other, with a delay of 0.1 seconds between each item.

Framer Motion Page Transitions

Framer Motion provides a seamless way to animate transitions between different pages in your React application. This can greatly enhance the user experience, making navigation feel smooth and responsive. Let’s explore how to implement page transitions using Framer Motion and React Router.

Setting Up React Router

First, we need to set up a React Router in our application. React Router is a popular library for managing routes in React applications. Here’s a basic setup:

import { BrowserRouter as Router, Switch, Route, Link } from 'react-router-dom';

function App() {
  return (
    <Router>
      <nav>
        <Link to="/">Home</Link>
        <Link to="/about">About</Link>
      </nav>

      <Switch>
        <Route path="/about">
          <About />
        </Route>
        <Route path="/">
          <Home />
        </Route>
      </Switch>
    </Router>
  );
}

So, we have two routes: Home and About. The Link component is used for navigation, and the Route component is used to render different components based on the current path.

Adding Framer Motion

To add page transitions, we will use the AnimatePresence and motion components from Framer Motion. AnimatePresence enables components to animate out when they’re unmounted, which is perfect for page transitions.

First, we need to wrap our Switch component with AnimatePresence. This will allow the routes to animate out when they’re unmounted:

import { AnimatePresence } from 'framer-motion';

// ...

<AnimatePresence>
  <Switch>
    {/* ... */}
  </Switch>
</AnimatePresence>

Next, we need to animate the routes themselves. We will replace the div elements in our Home and About components with motion.div elements:

import { motion } from 'framer-motion';

function Home() {
  return <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>Home</motion.div>;
}

function About() {
  return <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}>About</motion.div>;
}

And here we have it. Each page will fade in when it’s mounted and fade out when it’s unmounted.

Handling Exit Before Enter

By default, AnimatePresence waits for the exit animation to complete before starting the enter animation. This means that the new page won’t start fading in until the old page has finished fading out. If you want the two animations to overlap, you can add the exitBeforeEnter prop to AnimatePresence:

<AnimatePresence exitBeforeEnter>
  <Switch>
    {/* ... */}
  </Switch>
</AnimatePresence>

Now, the new page will start fading in as soon as the old page starts fading out.

Building a Drag-and-Drop UI with Framer Motion

Framer Motion simplifies the process of creating a drag-and-drop interface in your React application. With just a few lines of code, you can make any component draggable and animate it smoothly.

Making Elements Draggable

To make an element draggable, you need to add the drag prop to a motion component. Here’s an example:

import { motion } from 'framer-motion';

const DraggableItem = () => (
  <motion.div drag>This is a draggable item.</motion.div>
);

In this example, the div becomes draggable in both the x and y directions. If you want to restrict dragging to a specific direction, you can set drag to “x” or “y”.

Customizing Drag Constraints

Framer Motion allows you to constrain the draggable area by using the dragConstraints` prop. This prop takes an object that specifies the left, right, top, and bottom boundaries of the draggable area.

<motion.div drag dragConstraints={{ left: 0, right: 300, top: 0, bottom: 300 }} />

In this example, the div can only be dragged within a 300×300 pixel square.

Customizing Drag Elasticity

The dragElastic prop allows you to control the elasticity of the drag motion. A higher value will make the drag motion more elastic, while a lower value will make it more rigid. The default value is 0.8.

<motion.div drag dragElastic={1} />

In this example, the div will have a highly elastic drag motion.

Animating Drag Transitions

Framer Motion automatically animates the position of the draggable element when you release it. By default, it uses a spring animation, but you can customize this by using the dragTransition prop.

<motion.div drag dragTransition={{ bounceStiffness: 600, bounceDamping: 20 }} />

Here, the div will bounce back to its original position with a stiffness of 600 and a damping of 20 when you release it.

Integrating SVG Animations

Scalable Vector Graphics (SVG) provide a versatile approach to creating resolution-independent graphics for web applications. Framer Motion offers a straightforward and powerful API for animating SVGs, allowing you to create complex animations with ease.

Animating SVG Properties with Framer Motion

Framer Motion allows you to animate a variety of SVG properties. For instance, you can animate the fill property to change the color of an SVG element, or the pathLength property to animate the drawing of an SVG path.

Here’s an example of how to animate the fill property of an SVG circle:

import { motion } from 'framer-motion';

const MyComponent = () => (
  <motion.svg width="50" height="50">
    <motion.circle
      cx="25"
      cy="25"
      r="20"
      fill="blue"
      animate={{ fill: "red" }}
      transition={{ duration: 2 }}
    />
  </motion.svg>
);

In this example, the circle will gradually change its color from blue to red over 2 seconds.

Example: Animating an SVG Icon

Let’s take a look at a more complex example: animating an SVG icon. Suppose we have a heart icon that we want to animate when it’s clicked. We want the heart to scale up slightly when it’s hovered over, and we want it to fill with color when it’s clicked.

First, we will define our SVG icon:

const HeartIcon = ({ isFilled, ...props }) => (
  <motion.svg viewBox="0 0 24 24" {...props}>
    <motion.path
      fill={isFilled ? "red" : "none"}
      stroke="red"
      strokeWidth="2"
      d="M20.84 4.61a5.5 5.5 0 0 0-7.78 0L12 5.67l-1.06-1.06a5.5 5.5 0 0 0-7.78 7.78l1.06 1.06L12 21.23l7.78-7.78 1.06-1.06a5.5 5.5 0 0 0 0-7.78z"
    />
  </motion.svg>
);

Framer Motion also provides whileHover, whileTap , whileDrag and whileFocus helper props, that will temporarily animate a component to a visual state while a gesture is active. Like animate, these can either be set as an object of properties (each with their own transition prop), or the name of a variant.

Next, we will add the hover and click animations:

<HeartIcon
  isFilled={isLiked}
  whileHover={{ scale: 1.1 }}
  onClick={() => setIsLiked(!isLiked)}
  animate={isLiked ? { fill: "red" } : { fill: "none" }}
  transition={{ duration: 0.3 }}
/>

The heart icon will scale up by 10% when it’s hovered over, and it will fill with red color when it’s clicked.

Best Practices for Optimizing Framer Motion

Framer Motion is a powerful library for animations in React. However, like any tool, it’s important to use it wisely to ensure optimal performance. Here are some best practices for optimizing Framer Motion in your applications.

Using layoutGroup and layoutId for Shared Element Animations

Shared element animations are a common pattern in modern UI design where an element from one screen transitions into an element on another screen. Framer Motion provides the layoutId prop to create these animations with minimal code.

However, when animating between layouts, it’s often necessary to animate more than just a single element. For this, Framer Motion provides the layoutGroup prop. By adding layoutGroup to a parent element, all children with a layoutId will animate together as a group.

Leveraging Hardware Acceleration

Framer Motion leverages hardware acceleration for smoother animations. This is done by using the transform and opacity CSS properties, which are known to trigger hardware acceleration in browsers.

When defining your animations, try to stick to animating these properties as much as possible. For example, instead of animating itemVariants and height, consider animating scale instead.

Grouping Elements for Efficient Animations

When animating multiple elements together, it’s more efficient to group them into a single motion component. This reduces the number of elements that need to be animated, which can lead to smoother animations.

Applying Debounce or Throttle Techniques

When animating in response to rapid user interactions, it can be beneficial to apply debounce or throttle techniques. This can prevent unnecessary animations from being triggered and improve performance.

For example, if you’re animating an element in response to a scroll event, you might want to throttle the animations to only occur once every 100 milliseconds.

Tabular Importance of Adding Animations to a React App with Framer Motion

The table below summarizes the key benefits of integrating Framer Motion – the open-source motion library for animations in a React app:

Without AnimationsWith Framer Motion Animations
User ExperienceStatic, boring UISmooth, engaging animations
InteractivityNo visual feedback to user actionsAnimations show results of user interactions
Component TransitionsAbrupt component mounts/unmountsAnimated component transitions
Complex UIsHard to build complex animated UIsEasy to add complex animations
CodeMore code is needed to animate elementsConcise animation code
PerformancePotentially choppy animationsLeverages hardware acceleration
DocumentationNoneExcellent docs and examples
Community SupportSmaller communityPopular open-source project

What You Have Learned

In this comprehensive guide, we’ve explored the importance of adding animations to a React application using Framer Motion. Here’s a summary of what you have learned:

  • Framer Motion: You have learned about Framer Motion, a powerful animation library for React applications. It provides a simple and intuitive API for creating animations, making it easy to add dynamic and engaging animations to your app.

  • Components and APIs: You have learned about the core components and APIs of Framer Motion, including the motion component, AnimatePresence, and various props like initial, animate, exit, and transition.

  • Implementing Animations: You have walked through a step-by-step guide on implementing animations in a React app using Framer Motion. You have seen how to animate a notification tray, from setting up the project to adding animations and managing exit animations.

  • Variants: You have learned about variants in Framer Motion, which allows you to create cleaner and more coordinated animations. You have seen how to define and use variants, and how to stagger child animations for a smoother effect.

  • Page Transitions: You have learned how to add page transitions to your React application using Framer Motion and React Router, enhancing the user experience and making navigation feel smooth and responsive.

  • Drag-and-Drop UI: You have learned how to build a drag-and-drop interface using Framer Motion. You have seen how to make elements draggable, customize drag constraints and elasticity, and animate drag transitions.

  • SVG Animations: You have learned how to animate SVGs using Framer Motion. You have seen how to animate various SVG properties and how to animate an SVG icon.

  • Optimization: Finally, you have learned some best practices for optimizing Framer Motion in your applications. This includes using layoutGroup and layoutId for shared element animations, leveraging hardware acceleration, grouping elements for efficient animations, and applying debounce or throttle techniques.

Further Readings and Videos

By now, you should have a solid understanding of how to use Framer Motion, a production-ready motion library for React to enhance your React applications with animations. Whether you’re creating simple hover effects or complex multi-step animations, Framer Motion has the tools you need to bring your designs to life.

And that concludes this guide to optimizing responsive web design with Bootstrap margin utilities. However, if you are looking for more pre-made components to boost your responsive design workflow? Check out the Purecode AI component library!

Purecode AI boasts over 10,000 AI-generated components for CSS frameworks like Tailwind, Bootstrap, and MUI. Their designs are validated for quality and best practices.

Emmanuel Uchenna

Emmanuel Uchenna

Emmanuel is an experienced and enthusiastic software developer and technical writer with 4+ proven years of professional experience. He focuses on full-stack web development. He is fluent in React, TypeScript, VueJS, and NodeJS and familiar with industry-standard technologies such as version control, headless CMS, and JAMstack. He is passionate about knowledge sharing.