Animations are a powerful tool to enhance user experience, and when it comes to creating animations in React, Framer Motion is a popular library of choice. In this blog post, we'll explore 5 cool animations you can create in React using Framer Motion.
Check out this post on my blog
Framer Motion is a versatile animation library for React, known for its simplicity and powerful animations. If you're looking for an alternative, you can explore React Spring, which I've covered in my article here.
Now, let's dive into five cool animations you can create in React using Framer Motion!
1. Button Tap Animation
This is a really simple yet fun effect to add to your buttons. It adds a fun touch to your buttons by scaling them when tapped. To add this, we can make use of the whileTap
property. We can scale the button up or down within this property:
import { motion } from "framer-motion";
function App() {
return (
<motion.button
whileTap={{ scale: 0.85 }}
>
Click me!
</motion.button>
);
}
export default App;
The result will look somewhat like this:
2. Text Typing Animation
Text typing animations, created with Framer Motion, add a playful touch to engage users, useful for loading messages and chat simulations. To achieve this effect, we will take a sentence we want to display and convert it into an array of words. Next, we will map this array out and add an animation and transition on the opacity, as well as a delay that creates the typing effect.
import "./styles.css";
import { motion } from "framer-motion";
function App() {
const text = "Framer Motion is a really cool tool".split(" ");
return (
<div className="App">
{text.map((el, i) => (
<motion.span
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{
duration: 0.25,
delay: i / 10
}}
key={i}
>
{el}{" "}
</motion.span>
))}
</div>
);
}
export default App;
3. Stagger Animations
Stagger animations, as demonstrated in dropdowns and navigation menus, involve animating elements sequentially, each appearing one after the other, with a subtle delay distinguishing their appearances. You can create much more complex effects using this method as opposed to the ones mentioned above.
In this example, we will animate some menu items when a menu button is clicked. We will use the stagger
function alongside motion
and useAnimate
. Learn more about useAnimate here.
import { useAnimate, stagger, motion } from "framer-motion";
Start by creating an array that holds the list of items to be displayed in the menu. To achieve this effect, the list items are initially mapped within a <ul>
element. When the button is clicked, the <ul>
is first made visible. Then, the list items will animate in a staggered fashion one by one.
We will utilize the useAnimate
hook to generate the animations for both the <ul>
and <li>
elements. These animations will be triggered by a change in state, which can be toggled using the button.
import "./styles.css";
import { useState, useEffect } from "react";
import { useAnimate, stagger, motion } from "framer-motion";
export default function App() {
const [open, setOpen] = useState(false);
const [scope, animate] = useAnimate();
const items = ["Item 1", "Item 2", "Item 3", "Item 4"];
// the stagger effect
const staggerList = stagger(0.1, { startDelay: 0.25 });
// create the animations that will be applied
// whenever the open state is toggled
useEffect(() => {
animate(
"ul",
{
width: open ? 150 : 0,
height: open ? 200 : 0,
opacity: open ? 1 : 0
},
{
type: "spring",
bounce: 0,
duration: 0.4
}
);
animate(
"li",
open
? { opacity: 1, scale: 1, x: 0 }
: { opacity: 0, scale: 0.3, x: -50 },
{
duration: 0.2,
delay: open ? staggerList : 0
}
);
}, [open]);
return (
<div className="App" ref={scope}>
<motion.button onClick={() => setOpen(!open)} whileTap={{ scale: 0.95 }}>
Menu
</motion.button>
<ul>
{items.map((item, index) => (
<motion.li key={index}>{item}</motion.li>
))}
</ul>
</div>
);
}
4. Count Animation
This effect is commonly used for displaying numbers and statistics and is often used in countdown timers.
To implement this effect, we'll utilize MotionValues
to monitor the state and velocity of the values, and we'll employ the animate
function to specify the animation duration.
import { motion, useMotionValue, animate } from "framer-motion";
We will pass it an initial state or value which will be 0. Then we will count up to 50. Keep in mind that you need to round the count to make sure no decimal points are shown. For this, useTransform
will be used.
import "./styles.css";
import { motion, useMotionValue, useTransform, animate } from "framer-motion";
import { useEffect } from "react";
export default function App() {
const count = useMotionValue(0);
const rounded = useTransform(count, Math.round);
useEffect(() => {
const animation = animate(count, 50, { duration: 2 });
return animation.stop;
}, []);
return <motion.h1>{rounded}</motion.h1>;
}
In the code above, animation.stop
is being used to stop the animation when the component is unmounted. This ensures that the animation is terminated, and any resources associated with the animation are released.
5. Scroll Reveal Animations
Scroll reveal animations are a great way to make websites engaging and appealing to users. For instance, you can create effects like fading an element in or smoothly sliding it into view as it becomes visible on the screen. To create this effect, we can use the whileInView
and viewport
props. Here's an example of how to use these props to achieve a scroll reveal effect:
<motion.div
initial="hidden"
whileInView="visible"
viewport={{ once: true }}
/>
We can add animations and effects within the initial
and whileInView
props. Variants can also be used for this purpose. In the example below, we are going to slide in some elements when they come into view:
import React from "react";
import { motion } from "framer-motion";
function Card({ text, index }) {
return (
<motion.div
className="card"
initial={{
opacity: 0,
// if odd index card,slide from right instead of left
x: index % 2 === 0 ? 50 : -50
}}
whileInView={{
opacity: 1,
x: 0, // Slide in to its original position
transition: {
duration: 1 // Animation duration
}
}}
viewport={{ once: true }}
>
<p className="card-text">{text}</p>
</motion.div>
);
}
export default Card;
You can set viewport={{ once: true }}
to false if you want the effect to occur every time the element is scrolled into or out of view.
Thanks for reading! Check out this post on my blog too!