Guide to creating animations that spark joy with Framer Motion

December 15, 2020 / 15 min read

Last Updated: January 31, 2023

Over the past few months, Framer Motion went from being a fun tool I played with on the side to a core element of my frontend projects when it comes to adding a layer of interaction to my UIs. I went from knowing almost nothing about animations and transitions, to being able to orchestrate more complex animations involving lots of elements.

I've shared a lot of the animation work I sprinkled throughout my blog on Twitter, and a lot of you have asked me to share more code snippets. Thus I felt it was time for a little write-up!

In this post, you'll find a condensed guide containing everything I've learned when it comes to Framer Motion, the key concepts of animation, and how to use this library to create animations that spark joy through some interactive examples and widgets.

Anatomy of an animation

First, let's take a look at the main elements that define an animation. When working on one, whether it's to move an element, changing its shape, or color, I always try to answer the following 3 questions:

  1. ArrowAn icon representing an arrow
    "Where/how is my element at the beginning?" i.e the initial state
  2. ArrowAn icon representing an arrow
    "Where it needs to go or which shape it needs to take by the end?" i.e. the target state
  3. ArrowAn icon representing an arrow
    "How it's going to transition from the initial state to the end state?" i.e. the transition state

In the case of Framer motion, the library gives us a motion component which takes 3 properties (props) that let us define an answer to the 3 questions above:

  • ArrowAn icon representing an arrow
    initial: the state of our element at mount time.
  • ArrowAn icon representing an arrow
    animate: the state in which our element will be at the end of the animation.
  • ArrowAn icon representing an arrow
    transition: how our element goes from the initial state to the target state. This is where we can define which transition type we want to define, delays, or repetitions of the same transition.

There are many types of transitions available in Framer Motion so I added this little comparative visualization below for you to see the little nuances between some of the main types and tweak their respective options:

You can find the complete list of types and all their respective options in this section of the documentation.

Now that we went through the basics, let's take a look at our first examples! Below you will find a series of animated components that you can edit and tweak at will. As for what to tweak, the following list contains a few interesting points that you can check out:

  • ArrowAn icon representing an arrow
    **remove the **transition prop from the first component (Example1). Notice that this translation animation went from an ease type to a spring type. This comes from the "smart defaults" we just mentioned.
  • ArrowAn icon representing an arrow
    combine animations in Example2: change the second animation from a simple rotation to a rotation and a translation.

I added hints in the comments of the code to guide you. 😄

Using variants

Now that we've seen and tweaked our first Framer Motion based components, you might notice that, in the case of complex animations, things can quickly get messy. Defining everything inline can lead to your motion components being fairly hard to read but also a bit repetitive.

This is why one of my favorite features of Framer Motion is the ability to define animations in a declarative way through variants.

Variants are sets that have predefined animation objects, the kind of object we passed in the examples above in the animation prop.

The following is an example showcasing how you can leverage variants. Notice how we declared a set of variants within the buttonVariants object and how the respective keys of these variants are referenced in the motion component:

After seeing these variants the first time, like me, you might be wondering "wait, if everything is predefined, how can I make my animations based on some dynamic property?"

Well, don't you worry! Framer Motion lets you also define variants as functions. Each variant as a function can take one argument and return and animation object. That argument has to be passed in the custom prop of your motion component. The example below showcases an example of variant as function, the hover variant will return a different object whether the button is clicked or not. The state of the button isClicked is passed in the custom prop of the motion component.

Now that we know what variants are, let's try to work with them in the following playground. Let's try to:

  • ArrowAn icon representing an arrow
    make the first button scale on hover (for now, it only rotates).
  • ArrowAn icon representing an arrow
    make the button not scale back to its original size if it's been clicked on. Hint: you can use the custom prop we just mentioned above 💡.

Like in the first part, I left comments in the code to guide you!

Advanced animations using Motion Values

At this point, we know how to use the key features of Framer Motion to start building our own animations:

  • ArrowAn icon representing an arrow
    we know the main elements that define an animation ✅
  • ArrowAn icon representing an arrow
    we know how to use variants to define animations in a declarative way ✅

With those newly acquired skills, we can now look at on more concept that will allow us to build more advanced animations: Motion Values. In this part we will learn what are Motion Values and how to use them and also looked at a practical example to illustrate this concept: my own "Copy To Clipboard" button!

Motion Values

A MotionValue is an internal value to the Framer Motion library that "tracks the state and the velocity of an animating value". For more complex animation we may want to create our own MotionValue (quote from the docs), and then add them as inline style to a given component. To define a MotionValue, we need to use the useMotionValue hook.

A MotionValue can be practical when you want to have one animation depending on another one. For example, we may want to tie together the scale and the opacity of a component in such a way that, once the component reaches half of its targeted scale, the opacity should be equal to 100%.

To handle that kind of use case, Framer Motion gives us a second hook: useTransform that transforms an input MotionValue to another MotionValue through a function. The example below showcases how you can use these 2 hooks together:

Dissecting the "Copy To Clipboard" animation

You might have noticed that I sprinkled some animated SVG icons for my buttons throughout my blog ✨. One of my favorite is the "Copy To Clipboard" button on my code snippets, so I figured it would a great case study to look at together to illustrate some of the use cases for Motion Values. It uses both useMotionValue and useTransform to ensure that the opacity level of our checkmark icon is a function of its pathLength.

I added a "dissected" version of this component below to let you fully understand what is happening when clicking on the icon and how the Motion Values change throughout the transition. You can tweak the duration with the slider, and also visualize the MotionValue for the opacity and pathLength of the checkmark SVG.

When clicking on the button, you can see that the more the pathLength increases, the more the opacity of the checkmark increases as well following this function:

which is equivalent to the following code using Framer Motion's hooks:

Here's the code for the full implementation of this component:

It might seem dense at first, but you'll notice that it is composed of elements that we've seen individually in the previous sections and examples:

  • ArrowAn icon representing an arrow
    variants for the clipboard SVG and the checkmark SVG
  • ArrowAn icon representing an arrow
    useMotionValue and useTransform to intertwine the opacity and pathLength values together

Orchestration

For this last part, we will focus on how to orchestrate animations, especially with the two types of orchestration I used the most when building animations:

  • ArrowAn icon representing an arrow
    Delays and repetitions: "move to point A, then 2 seconds later move to point B then repeat"
  • ArrowAn icon representing an arrow
    Parent-Children: "parent appears first, then the children one after the other at 1-second interval"

Delays and repetition

This is perhaps the first type of orchestration you'll naturally think about when starting to experiment with more complex animations. Framer Motion lets you not only delay when an animation should kick-off but also delay any repetition of that same animation if needed.

I used delays and repetitions to orchestrate some of the micro-animations you can see in my Guide to CI/CD for frontend developers which were the first fairly complex animated components I implemented.

A few orchestration patterns have already been showcased in some of the previous examples out of necessity, but here's a more detailed example for you to play with:

  • ArrowAn icon representing an arrow
    you can try to change the repeat type from mirror to loop and observe the subtle change of repetition type.
  • ArrowAn icon representing an arrow
    make the animation repeat indefinitely instead of just 3 times.
  • ArrowAn icon representing an arrow
    make the initial delay 2s and every repeat delay 1s, you should observe the animation pausing between each repetition.

Parent-Children

A more advanced pattern for orchestration that I recently discovered is what I named "parent-children orchestration". It is pretty useful when you want to delay the animations of some children components in relation to an animated parent component.

Framer Motion gives us the delayChildren option for our transition object to do just that:

On top of that, what if we wanted to not only delay the children as a group but also delay each child based on its siblings, such as, make them appear 1s after their previous sibling appeared. Well, we're in luck, because there's an easy way to do that with the staggerChildren

What these 2 options exactly do might seem confusing at first. I wished I had some visual examples to really get a grasp on how they worked when I got started. I hope the following visualization will do just that!

In the widget below, you can tweak the values of beforeChildren and staggeredChildren and see how the resulting transition.

I used this type of orchestration to power the list of people who've shared or liked my articles that you can see at the end of each blog post. It's a component that quite a few people like, so I thought I could use it as a little example for you to interact and have fun with:

Conclusion

Wow, we just learned a lot of stuff about Framer Motion! We went from building very basic animations like translations to orchestrate more complex ones involving multiple components and also tie together multiple transitions using useMotionValue and useTransform. You have now learned pretty much everything I know about Framer Motion and can start sprinkling some amazing animations in your own frontend work.

This is my first time trying out this format involving interactive widgets and playgrounds to illustrate what I've learned, let me know what you think! Would you like to see more articles like this one? How would you improve the widgets and examples? I'm always looking to push this blog forward and would love to get some feedback.

Did you come up with some cool animations after going through this guide?

Don't hesitate to send me a message showcasing your creations!

Want to see more?

Here are some other Framer Motion related articles or examples I came up with:

Liked this article? Share it with a friend on Twitter or support me to take on more ambitious projects to write about. Have a question, feedback or simply wish to contact me privately? Shoot me a DM and I'll do my best to get back to you.

Have a wonderful day.

– Maxime