framer-motion vs gsap vs popmotion vs react-spring
Choosing the Right Animation Library for React and JavaScript
framer-motiongsappopmotionreact-springSimilar Packages:

Choosing the Right Animation Library for React and JavaScript

framer-motion, gsap, popmotion, and react-spring are leading libraries for adding movement and interactivity to web applications. framer-motion is built specifically for React, offering a declarative API that integrates tightly with component lifecycles and layout changes. gsap (GreenSock Animation Platform) is a robust, imperative engine that works with any JavaScript environment, known for precise timeline control and high performance. react-spring focuses on physics-based animations, using spring dynamics instead of fixed durations to create natural motion. popmotion serves as a functional, reactive animation engine that powers other libraries but can also be used directly for custom, low-level animation logic.

Npm Package Weekly Downloads Trend

3 Years

Github Stars Ranking

Stat Detail

Package
Downloads
Stars
Size
Issues
Publish
License
framer-motion031,9744.73 MB1212 months agoMIT
gsap024,7036.26 MB7a month agoStandard 'no charge' license: https://gsap.com/standard-license.
popmotion0-304 kB--MIT
react-spring029,0898.36 kB1388 months agoMIT

Framer Motion vs GSAP vs Popmotion vs React Spring: A Technical Deep Dive

Animation brings interfaces to life, but choosing the right engine affects everything from code structure to performance. framer-motion, gsap, popmotion, and react-spring all solve the same problem — moving elements on a screen — but they approach it from different angles. Let's compare how they handle real-world engineering tasks.

🏗️ Animation Model: Declarative vs Imperative vs Physics

The core difference lies in how you tell the library what to do.

framer-motion uses a declarative approach. You describe the end state in props, and the library handles the transition. This fits naturally into React's mental model.

// framer-motion: Declarative state
import { motion } from "framer-motion";

function Box() {
  const [isOpen, setIsOpen] = useState(false);
  return (
    <motion.div
      animate={{ scale: isOpen ? 1.2 : 1 }}
      onClick={() => setIsOpen(!isOpen)}
    />
  );
}

gsap uses an imperative approach. You select elements and command them to move using methods like .to() or .from(). This gives you direct control over execution.

// gsap: Imperative command
import { gsap } from "gsap";
import { useGSAP } from "@gsap/react";

function Box() {
  const { contextSafe } = useGSAP();
  const handleClick = contextSafe(() => {
    gsap.to(".box", { scale: 1.2, duration: 0.3 });
  });
  return <div className="box" onClick={handleClick} />;
}

react-spring uses a physics-based model. Instead of durations, you configure tension and friction. The animation calculates values based on physical forces.

// react-spring: Physics configuration
import { useSpring, animated } from "@react-spring/web";

function Box() {
  const [isOpen, setIsOpen] = useState(false);
  const props = useSpring({
    from: { scale: 1 },
    to: { scale: isOpen ? 1.2 : 1 },
    config: { tension: 200, friction: 20 }
  });
  return <animated.div style={props} onClick={() => setIsOpen(!isOpen)} />;
}

popmotion uses a functional reactive model. You create values and subscribe to updates, often wiring them manually to DOM elements.

// popmotion: Functional value stream
import { animate, value } from "popmotion";

const scale = value(1, v => element.style.scale = v);

function startAnimation() {
  animate({
    from: 1,
    to: 1.2,
    onUpdate: scale.set
  });
}

⏱️ Sequencing: Timelines vs State Changes

Complex animations often require steps to run one after another.

framer-motion handles sequences via the transition prop or by chaining variants. It works well for component-based sequences but can get verbose for long timelines.

// framer-motion: Variants for sequencing
const variants = {
  hidden: { opacity: 0, x: -100 },
  visible: { 
    opacity: 1, 
    x: 0,
    transition: { delay: 0.5 } 
  }
};
<motion.div variants={variants} animate="visible" />;

gsap shines here with its Timeline feature. You can stack animations precisely, overlap them, and control the whole sequence as one object.

// gsap: Timeline control
const tl = gsap.timeline();
tl.to(".box1", { x: 100 })
  .to(".box2", { x: 100 }, "<0.2"); // Start 0.2s before previous ends

react-spring does not have a built-in timeline. You manage sequencing by chaining springs or using useChain, which references multiple spring refs.

// react-spring: useChain for sequencing
const springRef1 = useSpringRef();
const springRef2 = useSpringRef();
// ... configure springs with refs ...
useChain([springRef1, springRef2], [0, 0.5]);

popmotion requires manual chaining. You use callbacks like onComplete to trigger the next animation function.

// popmotion: Manual chaining
animate({
  from: 0,
  to: 100,
  onComplete: () => {
    animate({ from: 100, to: 200 });
  }
});

🔄 React Integration & Re-renders

How the library plays with React's render cycle is critical for performance.

framer-motion is built for React. It minimizes re-renders by handling animations on a separate thread where possible and uses React state only for high-level logic.

// framer-motion: Optimized for React
// No manual refs needed for basic animations
<motion.div animate={{ x: 100 }} />

gsap traditionally manipulates the DOM directly, bypassing React. With the new useGSAP hook, it cleans up safely to avoid memory leaks, but you still manage refs explicitly.

// gsap: Direct DOM manipulation
const boxRef = useRef(null);
useEffect(() => {
  gsap.to(boxRef.current, { x: 100 });
}, []);

react-spring interpolates values outside the React render loop. It updates styles directly on the animated component, preventing unnecessary React commits.

// react-spring: Interpolation outside render loop
const { x } = useSpring({ x: 100 });
return <animated.div style={{ transform: x.to(v => `translateX(${v}px)`) }} />;

popmotion leaves integration up to you. In React, you typically combine it with useMotionValue (from framer-motion) or manage your own refs and requestAnimationFrame loops.

// popmotion: Manual React integration
useEffect(() => {
  const controls = animate({
    from: 0,
    to: 100,
    onUpdate: (v) => ref.current.style.left = v + "px"
  });
  return controls.stop;
}, []);

🖐️ Gestures & Layout

Handling user input and layout shifts is a common pain point.

framer-motion has built-in gesture props (whileHover, whileTap, drag). It also handles layout animations automatically with the layout prop.

// framer-motion: Built-in gestures and layout
<motion.div 
  whileHover={{ scale: 1.1 }} 
  layout 
  onClick={() => setIsOpen(!isOpen)} 
/>

gsap requires external plugins or manual event listeners for gestures. Layout changes must be measured and animated manually using Flip plugin or similar logic.

// gsap: Manual gesture handling
div.addEventListener("mouseenter", () => {
  gsap.to(div, { scale: 1.1 });
});

react-spring provides a useGesture hook (often via @use-gesture/react) to handle input. Layout animations require manual measurement of start and end positions.

// react-spring: External gesture hook
const bind = useDrag(({ movement: [mx] }) => ({ x: mx }));
return <animated.div {...bind()} style={{ x }} />;

popmotion provides input trackers like pointer but requires you to wire them to output values manually. Layout logic is entirely custom.

// popmotion: Custom input wiring
const x = value(0);
pointer(({ point: { x } }) => x.set(x));

📊 Summary Table

Featureframer-motiongsapreact-springpopmotion
Primary ModelDeclarative (React)Imperative (Timeline)Physics-basedFunctional Reactive
React Integration⭐⭐⭐⭐⭐ (Native)⭐⭐⭐⭐ (via hooks)⭐⭐⭐⭐⭐ (Native)⭐⭐ (Manual)
Timeline ControlVariants / Transitions⭐⭐⭐⭐⭐ (Robust Timeline)useChainManual Chaining
GesturesBuilt-in (whileHover)Manual / PluginsExternal HookManual Wiring
Layout AnimationAutomatic (layout prop)Manual / Flip PluginManual MeasurementCustom Logic
Best Use CaseUI InteractionsComplex SequencesPhysics / DragCustom Engines

💡 The Big Picture

framer-motion is the default choice for modern React apps. It removes the boilerplate of refs and effects, letting you animate components as if they were standard HTML. It handles the hard parts — like layout shifts and gestures — out of the box.

gsap remains the king of complex, time-based animation. If you are building a marketing site with scroll-triggered sequences or need to coordinate dozens of elements precisely, nothing beats its timeline API. It works everywhere, not just in React.

react-spring is the specialist for natural motion. If your app feels too robotic with standard transitions, springs add weight and momentum. It is excellent for draggables and interactive physics.

popmotion is the engine room. Unless you are building your own animation library or need to animate non-DOM targets (like Three.js or Canvas) with a functional approach, you will likely use Framer Motion or React Spring instead, as they build on these concepts for you.

Final Thought: For most React developers, start with framer-motion. It offers the best balance of power and simplicity. Reach for gsap when you need timeline precision, and react-spring when you need physics. Use popmotion only if you have very specific low-level requirements that the others cannot meet.

How to Choose: framer-motion vs gsap vs popmotion vs react-spring

  • framer-motion:

    Choose framer-motion if you are building a React application and want a declarative API that feels like native React. It is ideal for UI interactions, layout animations, and gesture handling without needing to manage refs or effects manually. It balances ease of use with powerful features like shared layout transitions.

  • gsap:

    Choose gsap if you need precise control over complex timelines, sequenced animations, or if you are working outside of React (vanilla JS or other frameworks). It is the industry standard for award-winning web experiences where performance and fine-grained control over every millisecond matter.

  • popmotion:

    Choose popmotion if you need a low-level, functional animation engine to build custom hooks or integrate with non-DOM targets like Canvas or WebGL. It is best for developers who want to construct their own animation abstractions rather than using a pre-built component library.

  • react-spring:

    Choose react-spring if your design requires physics-based motion, such as draggable items with momentum or natural decay. It is suitable for projects where fixed-duration transitions feel too rigid and you want animations that respond dynamically to user input.

README for framer-motion

Motion logo
Motion for React

An open source animation library
for React

npm version npm downloads per month jsDelivr hits (npm) NPM License

npm install motion

Table of Contents

  1. Why Motion?
  2. 🍦 Platforms
  3. 🎓 Examples
  4. ⚡️ Motion+
  5. 👩🏻‍⚖️ License
  6. 💎 Contribute
  7. ✨ Sponsors

Why Motion?

  • Simple API: First-class React, JavaScript, and Vue packages.
  • Hybrid engine: Power of JavaScript combined with native browser APIs for 120fps, GPU-accelerated animations.
  • Production-ready: TypeScript, extensive test suite, tree-shakable, tiny footprint. Batteries included: Gestures, springs, layout transitions, scroll-linked effects, timelines.

🍦 Platforms

Motion is available for React, JavaScript and Vue.

React

import { motion } from "motion/react"

function Component() {
    return <motion.div animate={{ x: 100 }} />
}

Get started with Motion for React.

Note: Framer Motion is now Motion. Import from motion/react instead of framer-motion.

JS

import { animate } from "motion"

animate("#box", { x: 100 })

Get started with JavaScript.

Vue

<script>
    import { motion } from "motion-v"
</script>

<template> <motion.div :animate={{ x: 100 }} /> </template>

Get started with Motion for Vue.

🎓 Examples & tutorials

Browse 330+ official examples, with copy-paste code that'll level-up your animations whether you're a beginner or an expert.

Over 100 examples come with a full step-by-step tutorial.

⚡️ Motion+

A one-time payment, lifetime-updates membership:

  • 330+ examples
  • 100+ tutorials
  • Premium APIs like Cursor and Ticker
  • Transition editor for Cursor and VS Code
  • AI skills
  • Private Discord
  • Early access content

Get Motion+

👩🏻‍⚖️ License

  • Motion is MIT licensed.

💎 Contribute

✨ Sponsors

Motion is sustainable thanks to the kind support of its sponsors.

Become a sponsor

Partners

Motion powers the animations for all websites built with Framer, the web builder for creative pros. The Motion website itself is built on Framer, for its delightful canvas-based editing and powerful CMS features.

Framer

Motion drives the animations on the Cursor homepage, and is working with Cursor to bring powerful AI workflows to the Motion examples and docs.

Cursor

Platinum

Linear Figma Sanity Sanity Clerk Greptile

Gold

Mintlify

Silver

Liveblocks Frontend.fyi Firecrawl Puzzmo Bolt.new

Personal