Introducing Framer Motion
In this article, we’ll take a closer look at how Framer Motion helps us in creating awesome animations. We’ll learn how motion components work and learn how to chain animations together. We’ll look into how to make gesture-triggered, timed, and scroll animations with Framer motion. Along the way, we’ll use the things we learn to build five demo applications I’ve set up to show us how we can integrate Framer Motion into real-world applications.
This tutorial will be beneficial to readers who are interested in integrating animations in their React application.
Note: This article requires a basic understanding of React and CSS.
What Is Framer Motion? #
Framer Motion is an animation library that makes creating animations easy. Its simplified API helps us abstract the complexities behind animations and allows us to create animations with ease.
Motion Components #
These are the building blocks of Framer motion. Motion components are created by prefixing motion
to your regular HTML and SVG element (e.g, motion.h1
). Motion components can accept several props, with the basic one being the animate
prop. This prop takes in an object where we define the properties of that component we want to animate. The properties we define will be animated when the component mounts in the DOM.
Let’s animate an h1 text using Framer Motion. First, we install the framer-motion library and import motion
.
Then we convert the h1 into a motion component.
This will cause the h1
to slide 20px to the right and move 20px up when it loads. When units aren’t added, calculations are done using pixels. However, you can explicitly set the units you want the calculations to be based on, animate={{x: "20rem", y: "-20rem"}}>
.
By default, a motion component will be animated from the state defined from its styles to those in the animate
prop. However, if we wanted to, we could hijack and define the initial animation state of the component using the initial
prop. While the animate
prop is used to define the behavior of components when they mount, the initial
prop defines their behavior before they mount.
If we want our h1 to come in from the left, we control that using the initial prop.
Now, when the h1
mounts, it slides in from the left.
We are not limited to a single animation. We can define a series of animations called keyframes
in an array of values. Each value will get animated in sequence.
The transition
prop allows us to define how the animations occur. With it, we define how values animate from one state to another. Among other things, we can define the duration
, delay
, and type
of animation using this prop.
Say we were to animate several motion components simultaneously, like in the code snippet below.
While this works, the variants
prop in Framer Motion enables us to extract our animation definitions into a variants object. Not only do variants
make our code cleaner, but they allow us to create even more powerful and complex animations.
Extracting our animation definitions into variants objects, we have this:
Instead of passing the animation definitions into a component’s initial
and animate
props directly, we extract these definitions into standalone variant objects. In the variant objects, we define variant names that describe each animation’s name as variants.
In the variants
prop, we pass in the name of the variant objects for each motion component and then pass in the animations to the initial
and animate
props.
We can take our current setup with variants further to reduce repetition. Using variants, we can propagate animation attributes down through the DOM from a parent motion component. For this to work, we create variants for the parent motion.div
with similar animation names in its variant object as its children. By doing this, we won’t have to pass the animation names’ to each child component. Behind the scenes, the parent element handles that for us.
Now we have a cleaner code with no repetitions. We turned the container div to a motion component so we could pass in the ContainerVariants
object we defined. Since we don’t define any animations on the container, we pass in empty objects to initial
and animate
. Your animation names must be the same in every variant object for the propagation to work.
Now we understand the basics of Framer Motion. Let’s begin building our fist of 5 demo applications.
Icon Shop #
We can create interactive animations based on gestures. Motion components are currently able to listen for hover, tap, pan, and drag gesture detection. We’ll be building this Icon Shop app using the whileHover
prop.
Components #
App.js
: this holds the heading texts.Card.jsx
: here, we define the animations for the icon cards.CardContainer.jsx
: we import and loop through the icons.styles.js
: create, style, and export the motion components. I used styled-components for styling the components.
Let’s start with App.js
.
We import the H1
and H2
motion components we created in the Styles.js
file. Since they are motion components, we use the initial
and animate
props to define their behavior before and when they mount. Here, we also import and display the CardContiner
component.
Now, the CardContainer.js
.
Here, we import the SVGs, the Container
motion component, and the Card
component.
Similar to H1
and H2
in App.js
, we define animations of the Container
using the initial
and animate
props. When it loads, it will create a cool effect of sliding in from the left of the browser.
Now, Card.js
Here, we create two variant objects with beforeHover
and onHover
animations. In the CardVariants
object, we don’t want to do anything initially, so beforeHover
is an empty object. onHover
we increase the scale of the card box.
In the IconVariants
object, we define the initial state of the IconBox
in its beforeHover
. We set its opacity to 0 and push it upwards by 50px. Then, in onHover
, we set the opacity back to 1, push it back to its default position, and change the transition type to tween
. Then we pass in the variants to their respective motion components. We make use of the propagation, so we don’t need to explicitly set the initial
and animate
props to the IconBox
component.
Animated Navbar #
We’ll build a simple Navigation component, and we’ll see how we can create timing relationships between parent and children motion components.
Components #
App.js
: this holds the heading texts.Styles.js
: create, style, and export the motion components. The components are styled using styled-components.
Let’s take a look at the App.js
file.
We create an isOpen
state that will be used to check if the Navbar is open or not. We create 3 variant objects, iconVariants
, menuVariants
, and linkVariants
where we define the animations for the SvgBox
, Nav
, and Link
motion components respectively. The iconVariants
is used to rotate the SvgBox
135deg when it’s hovered over. We don’t need to add “deg” to the value. In the menuVariants
, we control the top position of the Nav
like you would using the position
property in CSS. We toggle the top position of the Nav
based on the isOpen
state.
With variants, we can create timing relationships between parent and children motion components. We define the relationship between parent Nav
and its child, Link
using the when
property in the transition object. Here, set it to beforeChildren
, so the parent component’s animations will finish before the child’s animation begins.
Using the staggerChildren
property, we set a timing order for each link. Each link will take 0.5 seconds to appear one after the other. This creates a nice visual cue when the Nav
is opened. In the linkVariants
we animate the opacity and the vertical position of each link.
Here, we pass in the variants to their respective components. In the SvgBox
, we toggle the state of isOpen
whenever it’s clicked, then conditionally animate it based on the state. Like the SvgBox
, we conditionally animate the Nav
and the Link
s based on isOpen
’s state.
Animated Modal #
We’ll build a modal component and learn about Framer Motion’s AnimatePresence
, and how it allows us animate elements as they leave the DOM.
Components:
App.js
: we set up theshowModal
state here.Modal.jsx
: the actual animation work takes place here.Styles.js
: create, style, and export the motion components. The components are styled using styled-components.
Let’s look into App.js
We create a showModal
state that will be used to conditionally render the modal. The toggleModal
function will toggle the state whenever the ToggleButton
is clicked. ToggleButton
is a motion component, so we can define animations for it. When it mounts, it slides in from the left. This animation runs for 0.5 seconds. We also pass in the showModal
state to the Modal
through props.
Now, Modal.jsx
We import AnimatePresence
from framer-motion
. It allows us to set exit animations for components when they leave DOM. We conditionally render the Modal
based on the showModal
state. We define the animations for the ModalBox
and ModalContent
through their initial
and animate
props. There’s also a new prop here, exit
. Having AnimatePresence
as a wrapper allows us to add exit animations to ModalBox
in the exit
prop.
Scroll Animation #
We’ll use a combination of the useAnimation
hook and react-intersection-observer
to create scroll-triggered animations.
Components
App.js
: we set up the animations for theBox
component and render it inApp
Styles.js
: create, style, and export the motion components. The components are styled using styled-components.
The useAnimation
hook allows us to control the sequences in which our animations occur. We have access to controls.start
and controls.stop
methods that we can use to manually start and stop our animations. We pass in the initial hidden
animaton to StyledBox
. We pass in the controls we defined with the start
method to StyledBox
animate prop.
react-intersection-observer
’s useInView
hook allows us to track when a component is visible in the viewport. The useInView
hook gives us access to ref
, which we pass to the component we want to watch, and the inView
boolean, that tells us if that element is inView
or not. We use the useEffect
to call controls.start
whenever the element we’re watching, StyledBox
is in view. We pass in controls
and inView
as useEffect
’s dependencies. Also, we pass in the variants we defined, BoxVariants
to StyledBox
.
Hero Animation #
We’ll build a cool hero banner animation using the useCycle
hook. We’ll understand how useCycle
allows us to cycle through animations.
We define 3 variants, H1Variants
, TextVariants
, and BannerVariants
. However, our focus is BannerVariants
. We define 2 animations, animationOne
and animationTwo
in BannerVariants
. These are the animations we pass into the useCycle
to cycle through.
useCycle
works similar to the useState
hook. In the destructured array, animation
represents the animation that is active, whether animationOne
or animationTwo
. The cylceAnimation
function that cycles between the animation we defined. We pass in the animations we want to cycle through into useCycle
and call cylceAnimation
after 2 seconds in useEffect
.
At the end of everything, we pass in the variants to their respective components and watch the magic happen. With this, the Banner
will initially slide in from the right based on the animations we defined in animationOne
, and after 2 seconds, cycleAnimation
will be called which will trigger animationTwo
.
As a wise Pig once said, “that’s all folks.”
Conclusion #
We’ve gone through the basics of Framer Motion and seen some demo projects that give us a glimpse of the range of animations we can create. However, you can do so much more with it. I encourage you to dive into the docs and go wild.
Resources #
- Framer Motion Api Docs, Framer Motion
- react-intersection-observer, npm
- Framer Motion for React, NetNinja
Further Reading #
- Using AI To Detect Sentiment In Audio Files
- The End Of My Gatsby Journey
- Creating Accessible UI Animations
- Creating Custom Lottie Animations With SVGator

— Comments 3
Hola
Thanks a lot for your article. It really helped me to understand a few intermediate concepts I wanted to grasp, as a FM beginner.
@Joja:Hi Jola. I'm glad the article was helpful