← Blog

GSAP vs Framer Motion vs React Spring: Which Should You Use in 2026?

Comparing GSAP, Framer Motion, and React Spring for React animation. Bundle sizes, performance data, code examples, and honest recommendations.

GSAP vs Framer Motion vs React Spring comparison for React animation libraries in 2026

Every React developer hits this wall. You need animations. You search around. Three names keep coming up: GSAP, Framer Motion, React Spring. They all say they're the best. They all have fans who swear by them.

I've used all three in production. Here's what I actually think.

Quick answer: GSAP for anything complex or performance-critical. Framer Motion for layout animations and exit transitions in UI-heavy apps. React Spring if you want physics-based motion with a small API surface.

For most production work, I reach for GSAP.

What Is Each Library?

GSAP (GreenSock Animation Platform)

GSAP is a JavaScript animation library built by GreenSock. It's been the industry standard for professional web animation for over 15 years. Disney, Google, Amazon, Apple, and Stripe all use it.

It's not React-specific. It works anywhere: vanilla JS, React, Vue, Svelte, plain HTML. In React, you use the useGSAP hook from @gsap/react.

Core bundle size: 23KB gzipped (core, no plugins)

Key features:

  • Timeline sequencing with precise control over every keyframe
  • ScrollTrigger plugin for scroll-linked animations (pinning, scrubbing, parallax)
  • SplitText for character and word-level text animations
  • All plugins free since v3.12 (2023)
  • Runs at 60fps on mobile, not just desktop

Best for: Complex sequences, scroll animations, text reveals, award-level sites.


Framer Motion

Framer Motion is a React animation library built by the Framer team. It's declarative and feels very native to React. You animate by changing props on motion components.

It's React-only. There's no vanilla JS version.

Core bundle size: 46KB gzipped (full package, with tree shaking closer to 34KB for basic usage)

Key features:

  • AnimatePresence for exit animations when components unmount
  • Layout animations (layout prop) for smooth DOM reordering
  • Gesture animations (drag, hover, tap) with minimal code
  • Variants system for coordinating animations across component trees

Best for: UI animations, exit animations, layout transitions, drag interactions.


React Spring

React Spring is a physics-based animation library for React. Instead of duration-based tweens, it uses spring simulations. Animations feel natural because they behave like real physics.

Core bundle size: 18KB gzipped (@react-spring/web)

Key features:

  • Spring physics model (tension, friction, mass)
  • useSpring, useSprings, useTrail, useChain hooks
  • Interpolation system for complex value transforms
  • Works with react-three-fiber for 3D animations

Best for: Small-to-medium UI animations where natural motion feel matters more than precise timing.


Feature Comparison

FeatureGSAPFramer MotionReact Spring
Bundle size (gzipped)23KB34-46KB18KB
React-specificNoYesYes
Scroll animationsYes (ScrollTrigger)Basic onlyNo
Exit animationsManualYes (AnimatePresence)Manual
Layout animationsManualYes (layout prop)No
Timeline/sequencingYes (best in class)LimiteduseChain
Physics-basedNoPartialYes
SVG animationYesPartialNo
Text animationYes (SplitText)NoNo
Learning curveMediumLowLow
Free pluginsYes (since 2023)N/AN/A

Performance: The Real Difference

All three libraries can hit 60fps for simple animations. The gap shows up at scale.

How GSAP Handles Rendering

GSAP updates CSS properties directly via a single requestAnimationFrame loop. It batches all DOM reads and writes per frame. This avoids layout thrashing.

Critically: GSAP animations do not trigger React's reconciler. When a GSAP tween runs, React doesn't know about it. No virtual DOM diffing. No re-renders. Just direct DOM manipulation.

This matters on mobile. An iPhone 13 handles a 40-element staggered entrance animation at 60fps with GSAP. The same animation with React state updates causing re-renders can drop to 45-50fps.

How Framer Motion Handles Rendering

Framer Motion uses the Web Animations API for simple transforms and opacity (GPU-accelerated, no re-renders). But layout animations (layout prop) and some complex sequences go through React state, which triggers re-renders.

In practice: Framer Motion is fast for simple animations. Layout animations on large lists can get expensive. I've seen layout animations with 50+ items cause noticeable jank on mid-range Android.

How React Spring Handles Rendering

React Spring uses a shared value system similar to Framer Motion's. Most animations don't trigger full re-renders. The spring physics model is computed off the main thread where possible.

The issue: spring animations never truly "finish." They approach their target asymptotically. React Spring has a rest threshold, but small residual forces continue calculating until the threshold is hit. For many short animations this is imperceptible. For 30+ simultaneous springs it adds up.

Performance Summary

For a single button hover or a fade-in: all three perform identically. You won't see a difference.

For a page with 15+ scroll-triggered animations, complex sequencing, or 60+ elements animating together: GSAP has a clear advantage. Its architecture was built for this.


Developer Experience

GSAP in React

The modern way to use GSAP in React is the useGSAP hook. It handles cleanup automatically, scopes selectors to your component, and prevents the common memory leak issues with older GSAP + React setups.

script.js
import { useRef } from 'react'
import { gsap } from 'gsap'
import { useGSAP } from '@gsap/react'

export default function HeroSection() {
  const container = useRef(null)

  useGSAP(
    () => {
      gsap.from('.hero-title', {
        opacity: 0,
        y: 60,
        duration: 0.8,
        ease: 'expo.out',
      })

      gsap.from('.hero-subtitle', {
        opacity: 0,
        y: 40,
        duration: 0.8,
        delay: 0.15,
        ease: 'expo.out',
      })
    },
    { scope: container }
  )

  return (
    <section ref={container}>
      <h1 className="hero-title">Build Better Animations</h1>
      <p className="hero-subtitle">Copy-paste GSAP components for React.</p>
    </section>
  )
}

My take: Once you understand useGSAP, it feels clean. The imperative style takes getting used to if you're coming from React's declarative world. But it gives you control that declarative APIs can't match.

Pros:

  • Complete control over every frame
  • Timeline API is unmatched for complex sequences
  • Works the same in React, Vue, vanilla JS
  • Free plugins (SplitText, ScrollTrigger, MorphSVG, all of them)

Cons:

  • Steeper learning curve than Framer Motion
  • Exit animations require manual handling (no built-in unmount lifecycle)
  • More verbose for simple animations

Framer Motion in React

Framer Motion wraps your HTML in motion.* components. Props like initial, animate, and exit define the animation states.

script.js
import { motion, AnimatePresence } from 'framer-motion'

export default function Modal({ isOpen, onClose }) {
  return (
    <AnimatePresence>
      {isOpen && (
        <motion.div
          initial={{ opacity: 0, scale: 0.95 }}
          animate={{ opacity: 1, scale: 1 }}
          exit={{ opacity: 0, scale: 0.95 }}
          transition={{ duration: 0.2, ease: 'easeOut' }}
          className="modal"
        >
          <p>Modal content</p>
          <button onClick={onClose}>Close</button>
        </motion.div>
      )}
    </AnimatePresence>
  )
}

My take: This is genuinely elegant for component-level animations. AnimatePresence makes exit animations trivial. If you're building a UI component library or an app with lots of modal/drawer/popover transitions, Framer Motion is the right call.

Pros:

  • Low learning curve
  • AnimatePresence for exit animations is best in class
  • Layout animations with zero math
  • Feels native to React's declarative model

Cons:

  • Larger bundle than GSAP core
  • Complex sequences are awkward (variants can get messy)
  • No scroll-triggered animations without third-party libraries
  • Owned by Framer (a commercial company), not open governance

React Spring in React

React Spring uses hooks to return animated values. You apply those values to DOM elements via animated.* components.

script.js
import { useSpring, animated } from '@react-spring/web'

export default function AnimatedCard({ isVisible }) {
  const styles = useSpring({
    opacity: isVisible ? 1 : 0,
    transform: isVisible ? 'translateY(0px)' : 'translateY(30px)',
    config: { tension: 280, friction: 60 },
  })

  return (
    <animated.div style={styles} className="card">
      Card content
    </animated.div>
  )
}

My take: The spring config model is satisfying when you tune it right. Animations feel alive in a way that duration-based tweens don't. But the API surface is awkward for multi-step sequences. Chaining 4 springs in useChain is significantly more complex than a GSAP timeline.

Pros:

  • Smallest bundle
  • Natural, physics-based motion
  • Good for 3D with react-three-fiber
  • Less verbose than GSAP for simple cases

Cons:

  • No scroll animation support
  • No text animation support
  • Complex sequences are harder than they should be
  • Physics model can feel unpredictable until you know the config values

Bundle Size: What It Costs You

A 1KB increase in JavaScript adds about 2ms of parse time on a mid-range Android device (Lighthouse data, Moto G4 class).

LibraryBundle (gzipped)Est. parse overhead (mobile)
React Spring18KB~36ms
GSAP core23KB~46ms
Framer Motion (tree-shaken)34KB~68ms
Framer Motion (full)46KB~92ms

For context: Google recommends keeping total JavaScript under 200KB gzipped for fast initial load. A 46KB animation library is 23% of that budget.

This doesn't mean Framer Motion is a bad choice. It means you should weigh it if you're performance-sensitive or working on pages where load time matters.

GSAP's 23KB core covers most use cases. If you add ScrollTrigger, add another ~7KB. SplitText adds ~4KB. You're still under 35KB for a full production animation setup.


When to Use Each Library

Use GSAP if you're:

  • Building scroll-driven animations (ScrollTrigger is the best tool for this, period)
  • Animating text with character/word-level control (SplitText)
  • Sequencing complex multi-step animations across multiple elements
  • Building agency/portfolio/marketing sites where animation is the focus
  • Working across frameworks (you use React now but might use Vue or vanilla later)
  • Coming from after-effects or motion design (the timeline model is familiar)

Example project: A product launch page with scroll-pinned sections, text reveals, parallax layers, and a staggered hero entrance. This is GSAP territory.

script.js
// GSAP timeline: sequence 6 elements with 1 line of stagger
gsap.from('.feature-card', {
  opacity: 0,
  y: 50,
  duration: 0.6,
  stagger: 0.1,
  ease: 'expo.out',
  scrollTrigger: {
    trigger: '.features-section',
    start: 'top 80%',
  },
})

Use Framer Motion if you're:

  • Building a React app with lots of UI state transitions (modals, drawers, tabs, accordions)
  • You need exit animations when components unmount (AnimatePresence is genuinely the best solution here)
  • Working with drag interactions
  • Animating list reordering or layout changes

Example project: A Notion-like editor where cards reorder, modals open/close, and sidebar sections collapse. Exit animations and layout animations are everywhere. Framer Motion handles this with almost no custom code.

script.js
// Framer Motion: layout animation, zero math required
<motion.li layout key={item.id}>
  {item.content}
</motion.li>

Use React Spring if you're:

  • Building small-to-medium UI components where natural motion feel is the goal
  • Working with react-three-fiber for 3D
  • You want the smallest possible animation bundle
  • Spring physics model fits your use case (bouncy, elastic, natural)

Example project: A settings panel with toggle switches, accordion menus, and counter animations. React Spring's spring config makes these feel satisfying with minimal code.


My Verdict

I use GSAP for almost everything. The free plugins since 2023 removed the last reason I had to reach for alternatives. SplitText, ScrollTrigger, MorphSVG: all free, all in one package.

For Annnimate, every component is built with GSAP. Not because I'm biased (well, a little), but because when I need to reproduce animations reliably across projects with different frameworks and environments, GSAP just works. Predictable, well-documented, battle-tested.

Choose GSAP if:

  • Animation is a primary feature of what you're building
  • You need scroll animations
  • Performance on mobile matters
  • You want one library that works everywhere

Choose Framer Motion if:

  • You're building a React app (not a site) where UI state transitions dominate
  • You need exit animations without writing your own lifecycle handling
  • The team is less experienced with animation and needs a lower learning curve

Choose React Spring if:

  • Bundle size is critical
  • You're working in 3D with react-three-fiber
  • Spring physics model fits your specific use case

For most production sites: GSAP. It's what the best studios use for a reason.


Practical Starting Points

If you want to see what production-ready GSAP animations look like before writing them from scratch, I've built 50+ copy-paste components at Annnimate. Everything from scroll reveals to button hover effects to text animations. All with real code in React and HTML.


Key Takeaways

  • GSAP: 23KB gzipped, best performance, best for scroll and complex sequences
  • Framer Motion: 34-46KB gzipped, best for exit animations and layout transitions in React apps
  • React Spring: 18KB gzipped, physics-based, good for 3D and natural-feeling UI
  • For production sites and marketing pages: GSAP
  • For React apps with lots of UI state: Framer Motion