Toby Gates.
Animating a React component using Framer Motion

Animating a React component using Framer Motion

By Toby Gates - 14 February 2021


Introduction

Framer Motion is a production-ready animation and motion library for React.

Using it's simple devarative syntax we can add powerful animations while also keeping the codebase easy to read and maintain.

In the following article we'll look at how you can use Framer Motion to animate a component.

Adding Framer Motion to a project

First things first we'll need to install framer-motion from npm.

npm install framer-motion

Once installed, Framer Motion can be imported into each of your components via framer-motion.

Setting up the basic component

Here i've setup a basic React component. When the button is clicked a new item will be appended to the list.

Let's look at how we can animate this so that each new item on the list animates into place rather than just appearing on the screen.

Note: in this demo we are using i as the key for each of the mapped items for the purposes of this tutorial. This is anti-pattern and should not be used in a production setting. We would instead use a unique value from each of the items like an id. Read more about keys here.

Code:

import React, { useState } from "react";

const List = () => {
  const [items, setItems] = useState(["Item", "Item", "Item"]);

  const handleOnClick = () => {
    setItems((items) => [...items, "Item"]);
  };

  return (
    <div className="list">
      <button onClick={handleOnClick}>Add New Item</button>
      <ul>
        {items.map((item, i) => (
          <li key={i}>{item}</li>
        ))}
      </ul>
    </div>
  );
};

export default List;

Demo:

  • Item
  • Item
  • Item

Animating the component

Motion Components

Now we will look at how we can use Framer Motion to animate the list.

First we need to import motion from the Framer Motion package.

import { motion } from "framer-motion";

Motion components are the core of the Motion API. There's a motion component for every HTML and SVG element.

They work exactly the same as regular HTML and SVG elements, but with additional props to add animations.

Here's an example of a motion div component:

<motion.div>Lorem ipsum</motion.div>

Motion components are animated using the animate prop. This can accept an object, variant label(s), or a reference.

const variants = {
  hide: { opacity: 0, x: 100 },
  show: { opacity: 1, x: 0 },
};

return <motion.div initial="hide" animate="show" variants={variants} />;

Animating the list

Let's add a fade-in / bounce-in effect for each of the list items.

Code:

<motion.li
  key={i}
  initial="hide"
  animate="show"
  variants={{
    hide: { opacity: 0, x: 100 },
    show: { opacity: 1, x: 0 },
  }}
>
  {item}
</motion.li>

Demo:

  • Item
  • Item
  • Item

Dynamic Animations

The above use case is great if you want to animate new objects on load, however in some cases you may want to animate the whole list at once.

In the demo below you can see that each of the items load at the same time. Now let's look at how we can add a dynamic delay to each of the items.

Demo:

While mapping over the items array we have already set the index as i. We can make use of this to add a delay with an offset related to the index for each of the items by using the custom prop.

To make use of the custom value, we can convert any of the variants (in this case show) to be an arrow function.

We can then pass in i as an argument of the function.

Now that i is available to use we can set the transition to be delay: i * 0.1 so that each item will appear 0.1 seconds after the previous one.

Code:

<motion.li
  key={i}
  initial="hide"
  animate="show"
  variants={{
    hide: { opacity: 0, x: 100 },
    show: (i) => ({
      opacity: 1,
      x: 0
      transition: {
        delay: i * 0.1,
      },
    }),
  }}
  custom={i}
>
  {item}
</motion.li>

Demo:

Now when the list is loaded, each item loads in slightly delayed from the previous one.

The full code used in this demo is below so you can try it out for yourself:

import React, { useState } from "react";
import { motion } from "framer-motion";

const List = () => {
  const [items, setItems] = useState([]);

  const loadItems = () => {
    setItems(["Item", "Item", "Item"]);
  };

  const clearItems = () => {
    setItems([]);
  };

  return (
    <div className="list">
      {items.length ? (
        <button onClick={clearItems}>Clear Items</button>
      ) : (
        <button onClick={loadItems}>Load Items</button>
      )}
      {items.length !== 0 && (
        <ul>
          {items.map((item, i) => (
            <motion.li
              key={i}
              initial="hide"
              animate="show"
              variants={{
                hide: { opacity: 0, x: 100 },
                show: (i) => ({
                  opacity: 1,
                  x: 0,
                  transition: {
                    delay: i * 0.1,
                  },
                }),
              }}
              custom={i}
            >
              {item}
            </motion.li>
          ))}
        </ul>
      )}
    </div>
  );
};

export default List;

Conclusion

This is a minimal example for the purposes of a tutorial, but as you can see, Framer Motion is a powerful animation library that can be easily added to any React project.

Hopefully this has given you a brief understanding of how to use Framer Motion to animate a React component.

To find out more about Framer Motion visit https://www.framer.com/motion/.