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:
The Replay is a weekly newsletter for dev and engineering leaders.
Delivered once a week, it's your curated guide to the most important conversations around frontend dev, emerging AI tools, and the state of modern software.
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 0x: 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 0config: Specifies the configuration for the animation. In this example, the animation will have a duration of 1000msThe 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>

GitHub SpecKit brings structure to AI-assisted coding with a spec-driven workflow. Learn how to build a consistent, React-based project guided by clear specs and plans.

:has(), with examplesThe CSS :has() pseudo-class is a powerful new feature that lets you style parents, siblings, and more – writing cleaner, more dynamic CSS with less JavaScript.

Kombai AI converts Figma designs into clean, responsive frontend code. It helps developers build production-ready UIs faster while keeping design accuracy and code quality intact.

Discover what’s new in The Replay, LogRocket’s newsletter for dev and engineering leaders, in the October 22nd issue.
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 now