How to Animate Elements When in View on Scroll with Framer Motion
Animate React Apps with Framer Motion
Will released a full-length course on Framer Motion. Check it out if you're interested:
What is Framer Motion?
Framer Motion is a declarative animation library for React. It makes adding animations to React apps feel simple, even magical. Framer Motion basically hides away CSS transitions from you. You just say what you want, and BOOM the library will handle the css details of the animation.
The heart & soul of Framer Motion is Motion components. You can turn anything HTML or SVG element into a motion component by adding motion.
to the beginning of the element.
Example
Once an element becomes a motion component, it gets access to a bunch of new props like animate
, variants
and transition
to name a few.
Prerequisites
You would know how to create small applications in React and use features like Hooks. You are also familiar with CSS properties like opacity, scale, and transition. While this isn't an introduction to Framer Motion from scratch. You're not expected to have any Framer Motion knowledge. You will learn Framer Motion by building with it, and I'll explain new concepts along the way.
What You'll Be Building
You'll use Framer Motion with react-intersection-observer to trigger squares and scale animation to grow bigger when they come into view.
react-intersection-observer is a React flavored version of the Intersection Observer API to tell you when an element enters or leaves the viewport.
You will not build this application from scratch the starter code is here
You can view the final demo here
Set Up
You'll start with a React app with four Square
components rendered on-screen vertically.
App.js
The first thing you'll do is install Framer Motion and react-intersection-observer
Next, you'll bring in everything you need to create the animation.
- import
motion
and theuseAnimation
hook from Framer motion useEffect
from ReactuseInView
hook from react-intersection-observer
App.js
Don't worry. You will get an explanation on what each one does when it's time to use them.
Creating the Animation with Variants
To create the animation, you'll use a feature of Framer Motion call Variants (not be confused with Loki variants). Variants are objects that you use to define how you want the animation to look and reference the animation by name.
App.js
Here you created a variant object called squareVariants
. Inside the object, you have the property visible
that you passed an object as the value. When the element is visible
you want it to:
- have opacity be 1
- scale to 4x it's size
- have the transition from hidden to visible to have a duration of 1 second.
And when the element is hidden
you change opacity
and scale
to 0 so it's invisible.
Variants are dope because they free up your motion components from being overcrowded with a whole lot of props. You can put all the details of your animation in the variants object and reference it by adding the variants
prop and to a motion component.
App.js
Inside of the Square
component you:
- add
motion.
a the div - adding a
variants
prop - set it to the
squareVariants
object you created
Just adding the variants prop won't do anything. Your motion components need to know when you want these animations to start and what state you want them to end up in when the animation is finished.
For this, you need to add the intial
and the animate
prop.
App.js
Set the initial
prop to "hidden"
this tells Framer you want this div to have an opacity and scale of 0 (which is the value you define for hidden
in the squareVariants
object. ) when the pages loads. The initial
prop describes what state you want the animation to begin.
The animate
prop is the final state of the animation. Framer Motion automatically takes care of how the animation looks from initial to animate
. The animate
prop takes objects. Temporarily you'll pass in { scale:2 }
. This causes Square to scale to twice its size on page loads, animate
will be changed later.
Ready to pick up the pace?
Enter your email and receive regular updates on our latest articles and courses
We're here to help.
Sign up for our FREE email course
- ⭐️ Portfolio Building: Learn how to build a badass developer portfolio so you can land that next job
Add useAnimation and useInView to the Square Component
By default, Framer Motion runs animations once the page loads. The useAnimation
hook gives you access to the helper methods start
and stop
to give you more control over when the animation begins and ends. You'll use the start
method to set what animation gets get trigged when the element is in view.
Create a controls
variable and set to useAnimation()
and change the animate
prop to controls
.
App.js
Next, you'll bring in the useInView
hook from react-intersection-observer
. Use array destructing to pull out ref
and inView
from useInView
return.
App.js
The useInView
hook returns an array with a ref
and a Boolean inView
that checks if the status of an element being in view is true
or false
.
Trigger Animation with useEffect
Inside of the Square component useEffect
with an if statement. If inView
is true
set it run the controls.start()
method and pass it the squareVariants
property of "visible"
. Use controls
and inView
as the dependecy array. Finally, add a ref
attribute to the motion.div
and assign it the ref
from useInView
App.js
When the value of inView
changes aka when the element we referenced is in view, and inView
changes from false
to true
. It will run useEffect
to trigger controls.start()
to run the visible
animation.
This is a look at the full code
App.js
Conclusion
The demo app should have four boxes that grow to 4x their size when they are visible on the screen. You created this with minimal tweaking of the animation properties. Framer handled the annoying parts for you.
You learned how to create motion components, create variants to clean up your code, add the initial
and animate
props to tell Framer Motion how you want animations to start and end. Also, you used the useAnimation
hook to override Framer Motions default behavior of when the animation starts.
You also used react-intersection-observer to make it a lot easier to tell when our element is in view or not.
Next Steps
Take Will's course to get a better idea of what Framer Motion has to offer:
Resources
Ready to pick up the pace?
Enter your email and receive regular updates on our latest articles and courses
We're here to help.
Sign up for our FREE email course
- ⭐️ Portfolio Building: Learn how to build a badass developer portfolio so you can land that next job