# Animating a check icon in React with Framer Motion

## Introduction

Both React and Framer Motion are incredible technologies that help us build next-level user interfaces in a declarative way.

> If you're wondering what declarative programming is, I highly recommend checking out the article [Imperative vs Declarative Programming](https://ui.dev/imperative-vs-declarative-programming)

In this article, we'll create a reusable check icon component that animates by drawing itself in and out when it's mounted and unmounted by React. The animation utilises some core components from Framer Motion which are also described.

## Demo

%[https://codesandbox.io/embed/animating-a-check-icon-with-framer-motion-kqp8wm?fontsize=14&hidenavigation=1&module=%2Fsrc%2FApp.js&theme=dark] 

## Setting up the icon component

We'll use the `check` icon provided by [hero icons](https://heroicons.com/). Since we'll need to manipulate the `path` within the check icon `svg`, let's copy the JSX from hero icons into a new component `AnimatedCheckIcon`:

```jsx
function AnimatedCheckIcon() {
  return (
    <svg
      xmlns="http://www.w3.org/2000/svg"
      fill="none"
      viewBox="0 0 24 24"
      strokeWidth={1.5}
      stroke="currentColor"
    >
      <path
        strokeLinecap="round"
        strokeLinejoin="round"
        d="M4.5 12.75l6 6 9-13.5"
      />
    </svg>
  );
}
```

Nothing special here at the moment (of course, apart from the beautiful icon by the hero icons team), so let's install framer motion in preparation for adding animations to this component

```bash
npm install framer-motion
```

## Animating an SVG path with Framer Motion

The first step to animate a [path element](https://developer.mozilla.org/en-US/docs/Web/SVG/Element/path) is converting it to a `motion.path` component. [Motion components](https://www.framer.com/docs/component/) exist for all HTML and SVG elements and add animation super-powers to their DOM primitive counterparts.

These super-powers include defaults bundled with Framer Motion leading us to better looking and performant animations without worrying about the intricate details. The bare bones version to animate a motion component from one state to another requires passing the `initial` and `animate` prop specifying the styles for these states. Framer Motion then transitions between these states while providing satisfying defaults for its easing function and its duration at the least.

> Declarative programming at its best!

Amongst these super-powers, is the ability to animate [pathLength](https://developer.mozilla.org/en-US/docs/Web/SVG/Attribute/pathLength) for a `motion.path` component.

Let's take a look at what happens when we use `motion.path` in our `AnimatedCheckIcon` instead of `path` and specify the `initial` and `animate` props to take us from a `pathLength` of 0 to 1:

```jsx
<motion.path
  strokeLinecap="round"
  strokeLinejoin="round"
  initial={{ pathLength: 0 }}
  animate={{ pathLength: 1 }}
  d="M4.5 12.75l6 6 9-13.5"
/>
```

![motion-path-animate.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1664971846134/p9trK_J9P.gif align="left")

Great! We're already animating the check icon drawing itself in.

Similarly, if we switch up the initial and animate pathLengths to go from 1 to 0, we'll see the check icon erase itself:

```jsx
<motion.path
  strokeLinecap="round"
  strokeLinejoin="round"
  initial={{ pathLength: 1 }}
  animate={{ pathLength: 0 }}
  d="M4.5 12.75l6 6 9-13.5"
/>
```

![motion-path-erase.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1664972711176/ikCEn6Puu.gif align="left")

> The transition duration in the GIFs has been increased from the default value for clarity but is not displayed in the code snippets as we'll be touching on that later in the article

Okay, so we now know how to animate the `pathLength` but what happens if we mount/unmount this component? Let's render this component based on some state that we can toggle with a button. So we can now conditionally render our `<AnimatedCheckIcon />` like so:

```jsx
{isCheckIconVisible && <AnimatedCheckIcon />}
```

![motion-path-animation-initial.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1664973671721/NdhntJaFc.gif align="left")

We can see the path now animate when the component mounts but how do we specify an animation to run when it un-mounts?

## Adding an unmount animation with Animate Presence

Framer motion provides the [AnimatePresence](https://www.framer.com/docs/animate-presence/) component that helps us define animations that happen when a component is removed from the DOM by React.

This can be done by wrapping the component to be removed within `<AnimatePresence />` and adding the `exit` prop to the motion component defining its animation behaviour.

To make use of AnimatePresence, first let's add an `isVisible: boolean` prop to our `<AnimatedCheckIcon />` component that conditionally renders our icon based on the value provided:

```jsx
function AnimatedCheckIcon({ isVisible = true }) {
  return (
    isVisible && (
      <svg
        xmlns="http://www.w3.org/2000/svg"
        fill="none"
        viewBox="0 0 24 24"
        strokeWidth={1.5}
        stroke="currentColor"
      >
        <motion.path
          strokeLinecap="round"
          strokeLinejoin="round"
          initial={{ pathLength: 0 }}
          animate={{ pathLength: 1 }}
          transition={{ duration: 0.5 }}
          d="M4.5 12.75l6 6 9-13.5"
        />
      </svg>
    )
  );
}
```

We now need to nest our conditionally rendered icon within `<AnimatePresence />`:

```jsx
function AnimatedCheckIcon({ isVisible = true }) {
  return (
    <AnimatePresence>
      {isVisible && (
        <svg
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
          strokeWidth={1.5}
          stroke="currentColor"
        >
          <motion.path
            strokeLinecap="round"
            strokeLinejoin="round"
            initial={{ pathLength: 0 }}
            animate={{ pathLength: 1 }}
            transition={{ duration: 0.5 }}
            d="M4.5 12.75l6 6 9-13.5"
          />
        </svg>
      )}
    </AnimatePresence>
  );
}
```

> It's necessary that `<AnimatePresence>` component is outside of the `isVisible &&` condition as that allows Framer Motion to workaround React's limitation of not providing enough data to animate an element when it's being removed from the React tree

With our component wrapped in AnimatePresence, we can now add the `exit` prop to our `motion.path`:

```jsx
<motion.path
  strokeLinecap="round"
  strokeLinejoin="round"
  initial={{ pathLength: 0 }}
  animate={{ pathLength: 1 }}
  exit={{ pathLength: 0 }}
  d="M4.5 12.75l6 6 9-13.5"
/>
```

We specify exit animation to complete with `pathLength: 0` so the icon erases itself as we saw before. In summary, the props:

```jsx
initial={{ pathLength: 0 }}
animate={{ pathLength: 1 }}
exit={{ pathLength: 0 }}
```

declare that the component should transition from `pathLength` 0 to 1 when it mounts and 1 to 0 when it un-mounts.

If we connect the toggle state for rendering our icon from earlier but use the `isVisible` prop as follows:

```jsx
{<AnimatedCheckIcon isVisible={isCheckIconVisible} />}
```

we now see the unmount animation too:

![motion-path-moun-unmount-animation.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1664979441467/um1_U1woq.gif align="left")

## Disabling the initial mount animation

At this point, whenever our `<AnimatedCheckIcon />` component first mounts, it will animate itself based on the value of the `isVisible` prop. This might be the behaviour that's desired within a certain use case but perhaps not in others.

Thankfully, the `<AnimatePresence />` component exposes the `initial` prop that accepts a boolean value to handle this concern. Passing `false` suppresses the first mount animation while `true`, which is the default, runs the animation on the initial mount. Adding it as a prop to our icon component, to mimic this behaviour, our component interface now looks like the following:

```jsx
function AnimatedCheckIcon({ initial = true, isVisible }) {
  return (
    <AnimatePresence initial={initial}>
      {/* Rest of the component */}
    </AnimatePresence>
  )
}
```

## Fine-tuning the animation

Our animation is now set up but we can play around with yet another prop for Motion Components – [transition](https://www.framer.com/docs/transition/) – to make it even better! The `transition` prop can be used to fine-tune how the animation values go from one state to the other.

We'll make use of 3 properties within transition:

### 1\. Type

The `type` property accepts multiple options but two worth highlighting are `spring` and `tween`. Spring animations use [spring physics](https://www.framer.com/docs/transition/#spring) to transition between animation states while Tween is a duration-based type and can be customised with an easing function. Framer Motion picks the most appropriate defaults based on the styles being animated which in our case would be tween.

### 2\. Duration

The `duration` property specifies how long the transition takes to go from the initial to the animated state, specified in seconds. The default duration for tween animations is 0.3 seconds.

### 3\. Ease

The `ease` property accepts an [easing function](https://developer.mozilla.org/en-US/docs/Web/CSS/easing-function) to customise how fast the values change while animating over the specified duration. We'll use the built-in `ease-out` easing when the check icon mounts and `ease-in` when it un-mounts. The ease-out function starts quick but ends in a relaxed fashion while the ease-in animation starts in a relaxed fashion and ends quick. Try reverting these values in the sandbox to see how they affect our animation!

Putting these customisations together:

```javascript
<motion.path
  initial={{ pathLength: 0 }}
  animate={{ pathLength: 1 }}
  exit={{ pathLength: 0 }}
  transition={{
    type: "tween",
    duration: 0.3,
    ease: isVisible ? "easeOut" : "easeIn"
  }}
  strokeLinecap="round"
  strokeLinejoin="round"
  d="M4.5 12.75l6 6 9-13.5"
/>
```

we get the animation from the demo!

## Our final reusable animated check icon component

So, here's what we end up with as our reusable component that you can drop into your project for that well-polished micro-interaction:

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

function AnimatedCheckIcon({ initial = true, isVisible }) {
  return (
    <AnimatePresence initial={initial}>
      {isVisible && (
        <svg
          xmlns="http://www.w3.org/2000/svg"
          fill="none"
          viewBox="0 0 24 24"
          strokeWidth={1.5}
          stroke="currentColor"
          className="CheckIcon"
        >
          <motion.path
            initial={{ pathLength: 0 }}
            animate={{ pathLength: 1 }}
            exit={{ pathLength: 0 }}
            transition={{
              type: "tween",
              duration: 0.3,
              ease: isVisible ? "easeOut" : "easeIn"
            }}
            strokeLinecap="round"
            strokeLinejoin="round"
            d="M4.5 12.75l6 6 9-13.5"
          />
        </svg>
      )}
    </AnimatePresence>
  );
}
```

![animating-check-icon-path-framer-motion.gif](https://cdn.hashnode.com/res/hashnode/image/upload/v1664982658821/KXjFME99o.gif align="left")

In case, you're curious about the toggle button animation on the demo sandbox, it uses [Framer Motion gestures](https://www.framer.com/docs/gestures/) to animate its `scale` on hover and tap. You can check out the [code sandbox](https://codesandbox.io/s/animating-a-check-icon-with-framer-motion-kqp8wm?file=/src/App.js) for the full code and stay tuned for more articles on the topic.

Thanks for reading!
