How to Create A Sliding Sidebar Menu 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:
Animations do more than just look good. They can draw the user's attention to important information or let them know they can interact with certain elements.
Everything we do in the real world has motion. When you turn on the faucet to get a glass of water, you see the water stream into the glass and fill up. It would be weird if the water just teleported into the glass.
We do have a lot of motion on mobile apps, and for whatever reason, we've lost that on the web. Framer Motion is a React animation library that makes it simple and declarative to add animations to your React apps without being an animation expert.
What You Need To Know
This blog post will teach you a way to create a sliding navigation menu with Framer Motion. This post assumes you understand React features like JSX, functional components, and hooks.
You are not expected to know anything about animating on the web or Framer Motion. All concepts will be explained as you come across them, and links to the docs will be provided.
Getting Started
You'll start with a styled React app and get right into adding Framer Motion.
Here is the starting code:
App.js
Follow along with this tutorial using the demo CodeSandbox with Framer Motion already added here
Install Framer Motion
If you haven't already, the first thing you want to do is install Framer Motion into your project.
Now that you have Framer Motion installed, import motion
from Framer Motion.
App.js
Create a Motion Component and Start Animating
Motion components are what bring the magic of Framer Motion into your application. Add motion.
as a prefix to any HTML or SVG opening and closing tag to make it a motion component. We'll start with the <aside>
element in this example.
App.js
<aside>
is now a motion component that gets access to special props from Framer Motion that let you declaratively create your animations.
The first prop you'll add is initial
. This lets you set the state you want the element to be in on page load. The initial
prop takes an object with a key-value pair that says what property you want to change and how you want it to change.
Add the initial
prop to <aside>
.
App.js
Passing the initial
prop an object with a key of width
and a value of 0
tells Framer you want the width of the aside to be zero pixels on page load
Another prop you can use is animate
. This is is the state you want the animation to end at.
In this example, set the width
of the aside to 300
App.js
NOTE: Notice you only typed 300 not 300px. Framer automatically chooses px for you. To use another CSS unit like vw or em wrap the value in double quotes. For example -
animate={{ width: "30vw" }}
Now refresh the page and see the aside slide in 300 pixels.
Create Variants to Animate Children
Now you are getting into some fun with the variants
prop. Variants let you define your animation states outside of your element and reference the animation by any name you give.
The coolest part about variants is that when a parent element has the variants
prop, any child element in the React tree gets the animate
prop for free added behind the scenes, and you can have animations flow down the tree! Start by creating variants object for the aside element, with object keys aka variants labels for the states of the animation with values that are also objects.
App.js
NOTE: You can name variants and the variant labels whatever you want
Leave sideVariants
empty for now. Create another variant object for items from the links
array. With variant labels of open
and closed
. For closed
for use the value of {opacity : 0 }
, and { opacity: 1 }
for open
.
App.js
When the link elements are in the closed
state, they will be invisible, and when they are in the open
state, they will be completely visible.
You can more about CSS opacity here
Back in the sideVariants
, add a transition
object as the value. Transition is another prop that you can use in motion components, and it tells Framer Motion how you want the animation to go from one animation state to the next.
Now use the staggerChildren
. Since the links are wrapped in a div
and therefore are its children, staggerChildren
will animate each child item. You can set amount of time in between each animation as well!
For example, if staggerChildren
is 0.01, the first child will be delayed by 0 seconds, the second by 0.01, the third by 0.02, and so on.
You can also change which order they will animate with staggerDirection
. 1 staggers from the first to the last. -1 staggers in reverse from the last to the first. We'll use this later when the elements get removed from the DOM.
App.js
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 Variants to Motion Components
Now that we have our variants created. Add them to the motion components. Convert the wrapper div
and the a
tags to motion components.
Next, use the animations defined in the variant labels by referencing them in the motion component props. Add the initial
, animate
, and variants
props to the container div. Set initial
and to a string of "closed"
, animate
to "open"
and variants
to the sideVariants
object.
App.js
Now, you can add the variants
prop to the motion.a
tag and set it to itemVariants
.
App.js
When you refresh the page, the links should animate and become visible one by one, aka staggered. Notice how in order to animate the motion.a
tag, you didn't need to add the animate
prop to make the elements animate. The container div made it possible for all its children to be animated when we added the variants
prop.
Add useCycle hook to Switch Between Animation States
The useCycle
hook rotates or "cycles" through a set of animation states, and it works like the beloved useState
. You provide useCycle
an initial array of states, and it returns an array of two arguments.
You'll set the cycle variable to open and cycle between the true
or false
with a cycle function.
Start by importing useCycle
from Framer Motion. Then destruct open
and cycleOpen
from useCycle
just like you would with useState
. Pass false
and true
as arguments to useCycle
.
App.js
Next, you want to conditionally render the motion.aside
based on if the value of open
is true or false.
App.js
Finally, you want to add the onClick
event handler to the button, pass the cycleOpen
function. Then, add a ternary operator that changes the button's text to display open or closed depending on the value of open
.
App.js
Animate Components Removed from the React Tree with AnimatePresence
Right now, the aside
just pops out of vision when you click Close. That's a no-no for the app you're building. It's too stark, and the user loses the context of what is happening.
Framer Motion has the AnimatePresence
component that allows components to be animated out when removed from the React tree.
You need AnimatePresence
to activate exit animations because React doesn't have a lifecycle method that lets components know when they're going to be unmounted and allows them to delay the unmount until after an animation is over.
First, import AnimatePresence
Next, wrap the aside
motion component with AnimatePresence
.
App.js
Now that aside
is wrapped in AnimatePresence
, it has access to the exit
prop. The exit
prop is where you define how you want the element to animate when it leaves the React tree.
Here you'll pass the exit
prop this object. {width: 0, transition: { delay: 0.7, duration: 0.3 }}
.
App.js
With Framer Motion, you don't have to specify that you're using seconds for how long you want the animations to last since Framer defaults to seconds
Also, add an exit
prop to the container div around the motion.a
components. And set its animation to the variant label " closed"
App.js
This animates the aside
and the a
tags when removed from the DOM after the "Close" button is clicked.
Add Gestures to show Interactivity
The last thing you do is add a hover animation to the links in the menu and a subtle animation to let the user know that this element can be interacted with.
Framer Motion adds event listeners to React with gesture helper props. These props let you create animations based on different interactions with elements. Some of the gestures props are whileHover
, whileTap
, whileFocus
, and more.
In the example, you'll add a hover animtion. Add the whileHover
prop to the motion.a
component, and pass in an object with scale: 1.1
as the key-value pair.
App.js
Notice how you didn't have to create every detail of the animation. You just told Framer what you wanted to happen, and Framer Motion took care of the details.
Here is the final code
And here is the link to the finished code in a code sandbox
Conclusion
Now you have an animated sidebar that animates on a button press.
You learned how to use Framer Motions features like Gestures to animate on hover, Animate Presence to animate when an item leaves the DOM, and the useCycle hook to cycle through different animation states.
Next Steps
Take Will's course to get a better idea of what Framer Motion has to offer:
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