Editor’s note: This article was updated on 20 July 2023 to remove outdated React animation libraries and add more updated popular libraries, such as Anime.js and GreenSock.
For a React frontend developer, implementing animations on webpages is an integral part of your daily work, from animating text or images to complex 3D animations. Animation can help improve the overall user experience of a React application.
In this article, we’ll compare the top eight React animation libraries and evaluate each for popularity, developer experience, readability, documentation, and bundle size to help you choose the right library for your next React project.
Jump ahead:
React Spring is a modern animation library that is based on spring physics. It’s highly flexible and covers most animations needed for a user interface. Drawing inspiration from React Motion, React Spring inherits ease of use, while also borrowing some powerful performance attributes from React-Animated-CSS.
To see React Spring in action, install the library by using one of the commands below:
npm i @react-spring/web
yarn add @react-spring/web
Next, add the code below to create an animated Hello React Spring
text:
import { useSpring, animated } from "@react-spring/web"; import { useState } from "react"; function ReactSpring() { // State to keep track of the animation toggle const [state, toggle] = useState(true); // Define the animation using the useSpring hook const { x } = useSpring({ from: { x: 0 }, // Starting value of the animated property x: state ? 1 : 0, // Ending value of the animated property based on the state config: { duration: 1000 }, // Configuration for the animation, specifying the duration }); // Return the animated component return ( <div onClick={() => toggle(!state)}> <animated.div style={{ opacity: x.to({ range: [0, 1], output: [0.3, 1] }), transform: x .to({ range: [0, 0.25, 0.35, 0.45, 0.55, 0.65, 0.75, 1], output: [1, 0.97, 0.9, 1.1, 0.9, 1.1, 1.03, 1], }) .to((x) => `scale(${x})`), }} > Hello React Spring </animated.div> </div> ); } export default ReactSpring;
When you click on the div
, the above code animates both the opacity and scale of the contents. To understand better, let’s break it down step by step.
Within our component, state
is used to toggle the animation. When the div
is clicked, the toggle
function is called, changing state
from true
to false
, or vice versa. This triggers the animation due to the change in the x
value provided to the useSpring
Hook.
The useSpring
Hook is used to define the animation:
from
: Defines the starting values of the animated properties. In this case, we are animating the x
property, starting from 0
x
: This is the property that will be animated. It is dependent on the state
variable, so when state
is true
, x
will be 1
, and when state
is false
, x
will be 0
config
: Specifies the configuration for the animation. In this example, the animation will have a duration of 1000ms
The animated.div
component is used to wrap the contents that we want to animate. It uses the animated
wrapper from React Spring, allowing it to animate the styles applied to it. The animation itself is controlled by the style
prop of the animated.div
component. The style
object is defined using the x
value obtained from the useSpring
Hook.
Two CSS properties are animated in this example:
opacity
: The opacity of the content is interpolated from 0.3
to 1
based on the x
valuetransform
: The scale of the content is interpolated based on the x
value. The x.to
function maps specific input ranges to corresponding output values, effectively defining how the scale changes during the animationFramer Motion is a popular React animation library that makes creating animations easy. It boasts a simplified API that abstracts the complexities behind animations and allows developers to create animations with ease. Even better, it has support for server-side rendering, gestures, and CSS variables.
To install Framer Motion, run one of the following two commands in your terminal:
yarn add framer-motion
npm install framer-motion
Next, add the following code block to add cool yet simple animation to a square-shaped element:
import { useState } from "react"; import { motion } from "framer-motion"; import "./framer-motion.css"; // Import any CSS file if required function FramerMotion() { // State to keep track of the animation toggle const [isActive, setIsActive] = useState(false); // Return the animated component return ( <motion.div className="box" onClick={() => setIsActive(!isActive)} // Toggle the 'isActive' state on click animate={{ rotate: isActive ? [0, 90, 180, 270] : [270, 180, 90, 0], // Rotate the element based on 'isActive' state borderRadius: isActive ? [0, 20, 50] : [50, 20, 0], // Change border radius based on 'isActive' state }} ></motion.div> ); } export default FramerMotion;
When you click on the div
, the above code toggles the animation, rotating it in a circular motion and changing its border radius, creating a smooth and visually appealing effect.
Within our component, isActive
is used to toggle the animation. When the div
is clicked, the onClick
event handler is called, which toggles the value of isActive
between true
and false
. The animation is controlled using the animate
prop of the motion.div
component from Framer Motion. The animate
prop takes an object with properties that describe the animations to be applied to the element.
Then, the rotate
property animates the rotation of the element. When isActive
is true
, the element will rotate from zero degrees to 90 degrees, then to 180 degrees, and finally to 270 degrees. When isActive
is false
, the element will rotate in the reverse order, from 270 degrees to 180 degrees, then to 90 degrees, and finally back to zero degrees.
The borderRadius
property animates the border radius of the element. When isActive
is true
, the border radius will change from zero to 20 and then to 50. When isActive
is false
, the border radius will change in the reverse order, from 50 to 20 and finally back to zero.
reducedMotion
, which can scale down or entirely disable motion, making the experience more accessible for users who may be sensitive to motionLazyMotion
to reduce bundle size by synchronously or asynchronously loading some, or all, of the motion
component’s featuresFramer Motion cons
React Transition Group is a library that provides a set of components to help manage the animation of elements when they are added to or removed from the React component tree. It is commonly used in combination with React for creating smooth and seamless transitions for elements as they enter or exit the DOM.
To install the library, run one of the following commands in your terminal:
npm i react-transition-group
yarn add react-transition-group
Next, add this code block to create a basic fade animation using React Transition Group:
import { useState } from "react"; import { Transition } from "react-transition-group"; function ReactTransitionGroup() { const [show, setShow] = useState(true); const handleToggle = () => { setShow(!show); }; const duration = 300; // Animation duration in milliseconds // Custom styles for the enter animation const transitionStylesEnter = { entering: { opacity: 0 }, entered: { opacity: 1 }, }; // Custom styles for the exit animation const transitionStylesExit = { exiting: { opacity: 1 }, exited: { opacity: 0 }, }; return ( <div> <button onClick={handleToggle}>Toggle Fade</button> <Transition in={show} timeout={duration}> {(state) => ( <div className="fade-element" style={{ ...transitionStylesEnter[state], ...transitionStylesExit[state], transition: `opacity ${duration}ms`, // Apply the custom animation duration }} > Hello, this is a fade animation! </div> )} </Transition> </div> ); } export default ReactTransitionGroup;
When you click the "Toggle Fade"
button, the element will fade in or fade out smoothly, depending on the current value of the show
state. The Transition
component handles the custom animation logic using the provided styles and lifecycle hooks. To better understand, let’s break it down step by step:
Within our component, we define show
to control the visibility of the fading element. The handleToggle
function toggles the show
state when the "Toggle Fade"
button is clicked. Then, we set the duration
variable to control the animation duration for both enter and exit transitions. In this example, the duration is set to 300 milliseconds.
Next, we define two objects, transitionStylesEnter
and transitionStylesExit
, to specify the custom styles for the enter and exit animations, respectively. These styles are applied based on the current state of the transition using the state
argument provided by the render prop function inside the Transition
component.
Inside the return
statement, we use the Transition
component from React Transition Group. The Transition
component takes two main props: in
and timeout
. The in
props is a Boolean value that determines whether the element should be shown or hidden. In this case, it depends on the value of the show
state. Meanwhile, the timeout
prop displays the duration of the animation in milliseconds. In this example, we set it to the value of the duration
variable (300 milliseconds).
The Transition
component uses a render prop pattern, where the child function receives the current state
of the transition as an argument. The state
value can be one of the following strings: "entering"
, "entered"
, "exiting"
, or "exited"
. These states represent the different stages of the enter and exit transitions. Then, inside the render prop function, we render the fading element (<div className="fade-element">
) with inline styles.
The state
argument is used to apply the corresponding custom styles that we defined earlier for the enter and exit animations. Finally, the transition
property is set to apply the custom animation duration
for the opacity transition.
React Transition Group also comes with support for TypeScript, which can be installed using the command: npm i @types/react-transition-group
.
React Move is a library designed for creating beautiful and data-driven animations by leveraging the animation capabilities of D3.js. It was designed to support TypeScript out of the box and also supports custom tweening functions.
Tweening is short for “inbetweening,” the process of generating images for frame-by-frame animation between keyframes. React Move also features lifecycle events in its transitions, as well as allowing developers to pass on custom tweens in their animations. To install React Move, run one of the following two commands in your terminal:
npm install react-move
yarn add react-move
Next, add this code block to create animated bars using React Move:
import { useState, useEffect } from "react"; import { Animate } from "react-move"; import "./AnimatedBars.css"; // Import the CSS file with the styles // Define an array of colors for the bars const colors = ["#236997", "#52aaeb", "#a75e07", "#f4a22d", "#f95b3aff"]; // Define an array of data values for the bars' heights const data = [10, 26, 18, 14, 32]; function AnimatedBars() { // Initialize the state for the index of the data array const [index, setIndex] = useState(0); // Use the useEffect hook to set up the interval for updating the index useEffect(() => { // Set an interval to update the index every 2 seconds (2000 milliseconds) const intervalId = setInterval(() => { setIndex((prevIndex) => (prevIndex + 1) % data.length); }, 2000); // Clean up the interval when the component unmounts return () => { clearInterval(intervalId); }; }, []); // Render the animated bars using react-move return ( <div className="App"> {/* Create an SVG element to draw the bars */} <svg version="1.1" viewBox="0 0 240 135" width="100vw"> {/* Group the bars under a 'g' element */} <g> {/* Loop through the data array to create animated bars */} {data.map((value, i) => ( // Use the Animate component to animate the bars' heights <Animate key={i} start={{ height: 0 }} // Initial state of the animation (height starts from 0) enter={{ height: [value], timing: { duration: 500 } }} // Target state when a new data value is added update={{ height: [data[(i + index) % data.length]], // Target state when the index state changes timing: { duration: 500 }, }} > {/* Render a rect element for each bar */} {(state) => ( <rect x={60 + 30 * i} // X position of the bar y={115 - state.height} // Y position of the bar (height changes based on state) width={24} // Width of the bar height={state.height} // Height of the bar (changes based on state) fill={colors[i % colors.length]} // Fill color of the bar (based on the colors array) /> )} </Animate> ))} </g> </svg> </div> ); } export default AnimatedBars;
The code above renders a set of animated bars using the React Move library with changing height and color every two seconds. To understand better, let’s break it down.
First, we define an array of colors
and data
to be used to style the bars and determine their heights. Meanwhile, the index
state variable will be used to update the bars. Then, the useEffect()
Hook sets up an interval to update the index
state every two seconds. This will trigger the animation and update the bars based on the data array.
To render the animated bars, we group the bars using a <g>
element inside the <svg>
element. Then, we loop through the data
array and create an Animate
component for each value. For each Animate
component, we specify the start
, enter
, and update
configurations for the animation:
start
: The initial state of the animation. The height starts from zeroenter
: The target state of the animation when a new data value is added. The height is set to the corresponding value from the data
arrayupdate
: The target state of the animation when the index
state changes. Height is updated to the corresponding value from the data
array using the index
stateThen, inside the Animate
component, we define the animation and render a <rect>
element for each data value:
<rect>
elements represent the barsx
, y
, width
, and fill
attributes are set to style each bar based on its index and data valueThe Remotion React library was created in 2021 to create animations using HTML, CSS, and JavaScript. With Remotion, you can create videos as well as play and review them on your browser while using React components and compositions.
Remotion also allows developers to scale video animation and production using server-side rendering and parametrization. Parametrization is the process of finding equations of curves and surfaces using equations, which can be very useful in creating meshes for videos. You can initialize a new Remotion video by running either of the commands below in your terminal:
npm init video
yarn create video
A video is a function of images over time. If you change content every frame, you’ll end up with an animation. To create one using Remotion, add the following lines of code:
import { useVideoConfig } from "remotion"; export const MyVideo = () => { const { fps, durationInFrames, width, height } = useVideoConfig(); const opacity =frame >= 30 ? 1 : frame / 30; return ( <div style={{ flex: 1, textAlign: "center", fontSize: "9em", opacity: opacity, }} > This {width}px x {height}px video is {durationInFrames / fps} seconds long. </div> ); };
In the code above, we added animation properties using opacity
. We also added a video animation using the useVideoConfig()
Hook. When creating a video animation, we’d need the width
, height
, durationInFrames
, and fps
parameters in Remotion. You can read more about them here.
React Reveal is a high-performance and easy-to-use library for adding animations to React applications. Unlike most animation libraries, React Reveal only reveals animations and effects if you scroll down to the animated element, not during load time. This improves page speed by allowing animation components to be lazy-loaded.
It’s also important to note that React Reveal supports higher order components for some of its features. You can install React Reveal with the command below:
npm install react-reveal
To create a cool yet simple animation, add the following lines of code:
import { Bounce, Slide } from "react-reveal"; import Shake from "react-reveal/Shake"; import RubberBand from "react-reveal/RubberBand"; function ReactReveal() { return ( <> <Bounce left> <h1>Bounce</h1> </Bounce> <Slide left> <h1>Slide</h1> </Slide> <Shake> <h1>Shake</h1> </Shake> <RubberBand> <h1>Rubberband</h1> </RubberBand> </> ); } export default ReactReveal;
In the code block above, we easily added various animations to elements, providing a visually appealing user experience.
Anime.js is a lightweight JavaScript animation library with a simple, yet powerful API. It makes animating CSS properties, SVG elements, DOM attributes, and JavaScript objects a breeze.
To install Anime.js, run one of the following commands:
npm install animejs
yarn add animejs
To create a cool SVG animation, add the lines of code below:
import { useEffect, useRef } from "react"; import anime from "animejs"; function Anime() { const circleRef = useRef(null); const animateCircle = () => { // Get the DOM element to animate const circle = circleRef.current; // Use AnimeJS to create the animation anime({ targets: circle, cx: anime.random(10, 500), // Random x position between 10 and 500 cy: anime.random(10, 500), // Random y position between 10 and 500 duration: 2000, // Animation duration in milliseconds easing: "easeInOutQuad", // Easing function for smooth animation complete: animateCircle, // Repeat the animation infinitely }); }; useEffect(() => { animateCircle(); }, []); return ( <svg width="500" height="500"> <circle ref={circleRef} r="30" fill="blue" /> </svg> ); } export default Anime;
In the code above, a circle moves randomly on the screen within the specified coordinate range and keeps looping infinitely. To understand better, let’s break it down.
Inside the component, a useRef
Hook is used to create a reference called circleRef
, which is used to get a reference to the SVG circle element that needs to be animated.
Meanwhile, the animateCircle
function is responsible for animating the SVG circle element. Inside the function, the DOM element to animate is obtained using the circleRef.current
. Then, Anime.js is used to create an animation using the anime()
function. The targets
option specifies the circle element to animate, and the cx
and cy
properties are animated with random values between 10 and 500, creating a random movement of the circle.
Then, the duration
option sets the animation duration to 2000 milliseconds (two seconds), while the easing
option specifies the easing function used for smooth animation. Finally, the complete
option sets the animateCircle
function to be called again when the animation is completed, creating an infinite loop. The r
attribute sets the radius of the circle and the fill
attribute sets the circle’s color.
GSAP (GreenSock Animation Platform) is a robust and widely-used animation library for creating high-performance animations and interactive web experiences. It has been a popular choice among developers for many years. Known for its speed, flexibility, and smoothness, GSAP empowers developers to craft seamless animations with ease.
You can install GSAP with one of the commands below:
npm install gsap
yarn add gsap
To create a cool scroll triggered animation, add the following code:
import { useLayoutEffect, useRef } from 'react'; import { gsap } from 'gsap'; import { ScrollTrigger } from 'gsap/ScrollTrigger'; gsap.registerPlugin(ScrollTrigger); export default function Scroll() { const main = useRef(); useLayoutEffect(() => { const ctx = gsap.context((self) => { const boxes = self.selector('.box'); gsap.from(boxes, { x: -500, // Start from left (-100px) opacity: 0, duration: 1, stagger: 0.2, // Add stagger effect for sequential animation scrollTrigger: { trigger: main.current, start: 'top 80%', // Adjust the start position for the effect end: 'bottom 20%', // Adjust the end position for the effect scrub: true, }, }); }, main); // <- Scope! return () => ctx.revert(); // <- Cleanup! }, []); return ( <div> <section className="section flex-center column"> <h2>Scroll down to see the animation!!</h2> </section> <div className="section flex-center column" ref={main}> <div className="box">Box 1</div> <div className="box">Box 2</div> <div className="box">Box 3</div> <div className="box">Box 4</div> <div className="box">Box 5</div> </div> <section className="section"></section> </div> ); }
On page scroll, the boxes will come from the left side of the screen with a stagger effect, and their opacity will increase, creating a smooth animation.
ScrollTrigger
, which is imported from GSAP’s ScrollTrigger plugin, enables animations based on scroll positions. gsap.registerPlugin(ScrollTrigger);
is used to register the plugin with GSAP. Then, const main = useRef();
creates a ref
called main
to reference the main container.
To set up the animation, gsap.context()
is used to create a context for managing animations scoped to the main
container. Then, gsap.from()
is used to create the animation. The boxes
element is selected using self.selector('.box')
, and the animation targets each box element, starting from -500
units to the left (x: -500
) and with opacity: 0
.
The animation duration is set to 1
second, and stagger: 0.2
is used to add a stagger effect for sequential animations among the boxes. Then, scrollTrigger
specifies the trigger options for the animation, which will be triggered based on the scroll position.
start: 'top 80%'
specifies that the animation starts when the top of the main
container is at 80% of the viewport’s height. Meanwhile, end: 'bottom 20%'
specifies that the animation ends when the bottom of the main
container is at 20% of the viewport’s height. Finally, scrub: true
enables the scrub feature, which changes the animation progress based on scroll position. The animation will control the x
position and opacity as specified in the animation setup.
Regardless of the project you’re working on, numerous animation libraries exist that can help you create user-friendly animations and transitions easily and quickly. From this list and as of this writing, Anime.js has the most stars on GitHub, while React Transition Group wins in terms of weekly downloads on npm. However, other libraries may offer specific features that you need, such as tweening with React Move or lifelike animations with React Motion.
Many of these libraries are customizable and include great built-in features and changes. Hopefully, going through pros and cons, you can choose the right library for your next React application.
Install LogRocket via npm or script tag. LogRocket.init()
must be called client-side, not
server-side
$ npm i --save logrocket // Code: import LogRocket from 'logrocket'; LogRocket.init('app/id');
// Add to your HTML: <script src="https://cdn.lr-ingest.com/LogRocket.min.js"></script> <script>window.LogRocket && window.LogRocket.init('app/id');</script>
Hey there, want to help make our blog better?
Join LogRocket’s Content Advisory Board. You’ll help inform the type of content we create and get access to exclusive meetups, social accreditation, and swag.
Sign up nowIt’s easy for devs to default to JavaScript to fix every problem. Let’s use the RoLP to find simpler alternatives with HTML and CSS.
Learn how to manage memory leaks in Rust, avoid unsafe behavior, and use tools like weak references to ensure efficient programs.
Bypass anti-bot measures in Node.js with curl-impersonate. Learn how it mimics browsers to overcome bot detection for web scraping.
Handle frontend data discrepancies with eventual consistency using WebSockets, Docker Compose, and practical code examples.