framer-motion, popmotion, react-motion, and react-spring are libraries designed to handle declarative animations in React applications. framer-motion is a production-ready solution offering a rich API for gestures, layout animations, and complex sequences. react-spring is a physics-based library that interpolates values using spring dynamics rather than fixed durations, providing natural movement. popmotion serves as the functional, framework-agnostic engine powering framer-motion, suitable for custom implementations. react-motion is the legacy predecessor to these modern tools, now deprecated and no longer recommended for new development due to performance limitations and lack of maintenance.
Building smooth, performant interfaces in React requires more than just CSS transitions. The ecosystem offers several libraries to handle animation logic, each with a distinct architectural approach. framer-motion, react-spring, popmotion, and the legacy react-motion solve the same problem but differ significantly in their underlying mechanics, API design, and maintenance status. Let's break down how they work in real engineering scenarios.
The biggest divide in this group is how they calculate movement. react-spring and react-motion rely on physics-based springs. You define mass, tension, and friction, and the library calculates the curve. framer-motion defaults to keyframe-based animations (duration and easing) but supports springs optionally. popmotion is a functional engine that exposes the raw loop.
framer-motion uses a declarative API where you define the start and end states. It handles the interpolation automatically.
// framer-motion: Keyframe/Duration based by default
import { motion } from "framer-motion";
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5, ease: "easeInOut" }}
/>
react-spring forces you to think in springs. There is no "duration" property; you tune the physical properties to get the timing you want.
// react-spring: Physics based
import { useSpring, animated } from "@react-spring/web";
const props = useSpring({
from: { opacity: 0, transform: "translateY(20px)" },
to: { opacity: 1, transform: "translateY(0px)" },
config: { tension: 280, friction: 60 }
});
<animated.div style={props} />
popmotion exposes the animate function directly. You manually subscribe to value updates and apply them to the DOM or state.
// popmotion: Functional/Imperative
import { animate } from "popmotion";
const div = document.querySelector(".box");
animate({
from: 0,
to: 100,
onUpdate: (latest) => {
div.style.transform = `translateX(${latest}px)`;
}
});
react-motion (Legacy) also used springs but required a render-prop pattern that often caused performance bottlenecks in older React versions.
// react-motion: Legacy Spring API
import { Motion, spring } from "react-motion";
<Motion defaultStyle={{ x: 0 }} style={{ x: spring(100) }}>
{interpolatingStyle => (
<div style={{ transform: `translateX(${interpolatingStyle.x}px)` }} />
)}
</Motion>
Before diving deeper, we must address react-motion. The library is deprecated. The maintainer has archived the repository and explicitly advised against using it for new projects. It lacks support for modern React features like Concurrent Mode and suffers from unnecessary re-renders.
react-motion should not be used. If you encounter it in a legacy codebase, prioritize refactoring to framer-motion or react-spring.
// β DO NOT USE: react-motion is deprecated
// Migration path: Switch to framer-motion for similar declarative syntax
In contrast, framer-motion and react-spring are actively maintained with frequent updates for React Strict Mode and Server Components.
One of the hardest problems in UI is animating layout changes (e.g., when an item is removed from a list and the others shift). framer-motion solves this with its layout prop, which automatically calculates the delta and animates the transition.
framer-motion handles layout shifts automatically with a single prop.
// framer-motion: Automatic layout animation
import { motion } from "framer-motion";
<motion.div layout ID="item-1">
{/* Content changes size, div animates smoothly */}
</motion.div>
react-spring does not have a built-in "layout" prop. You must manually measure elements using refs and feed those dimensions into the spring physics.
// react-spring: Manual layout measurement
import { useSpring, useMeasure } from "@react-spring/web";
const [ref, { height }] = useMeasure();
const props = useSpring({ height: height || 0 });
<animated.div style={props} ref={ref}>
{/* Content */}
</animated.div>
popmotion provides no layout helpers. You would need to write significant custom logic to measure DOM nodes and drive the animation loop.
// popmotion: Fully custom layout logic required
const element = ref.current;
const startHeight = element.offsetHeight;
// ... calculate new height ...
animate({ from: startHeight, to: newHeight, ... });
react-motion lacked native layout projection, requiring complex wrapper calculations similar to react-spring but with higher performance costs.
// react-motion: Complex manual calculation required
// No native layout prop available
For gestures (drag, pinch, hover), framer-motion includes built-in hooks like useDragControls and props like drag. react-spring offers useGesture (often via a separate companion package @use-gesture/react), while popmotion requires manual event listener attachment.
Coordinating multiple animations (e.g., staggering a list entrance) is common. framer-motion simplifies this with variants and automatic orchestration.
framer-motion uses variants to define states and orchestrates children automatically.
// framer-motion: Declarative orchestration
const container = {
hidden: { opacity: 0 },
show: {
opacity: 1,
transition: { staggerChildren: 0.1 }
}
};
<motion.ul variants={container} animate="show">
<motion.li variants={item} /> {/* Staggers automatically */}
</motion.ul>
react-spring requires you to manage delays manually within the config or use useTrail for simple lists.
// react-spring: Manual delay or useTrail
import { useTrail } from "@react-spring/web";
const trail = useTrail(items.length, {
from: { opacity: 0 },
to: { opacity: 1 },
delay: 200 // Manual delay management
});
popmotion requires you to chain animate calls manually using promises or callbacks.
// popmotion: Manual chaining
animate({ from: 0, to: 100 }).then(() => {
animate({ from: 100, to: 200 });
});
react-motion had no built-in orchestration helpers, forcing developers to manage timing state manually.
// react-motion: No orchestration helpers
// Developers managed timing via state or external libs
framer-motion is built specifically for React (and React Native) and integrates deeply with the component lifecycle. popmotion is framework-agnostic, making it useful for Vanilla JS, Vue, or Svelte projects, but it lacks React-specific optimizations out of the box.
framer-motion works seamlessly with React Server Components and Strict Mode.
// framer-motion: Optimized for modern React
"use client";
import { motion } from "framer-motion";
// Works without extra configuration
react-spring also supports modern React patterns but sometimes requires careful handling of animated components to avoid hydration mismatches.
// react-spring: Requires animated wrappers
import { animated } from "@react-spring/web";
// Must wrap DOM nodes with 'animated' to subscribe to updates
popmotion has no React-specific build; you integrate it wherever you can access the DOM.
// popmotion: Framework agnostic
// Import directly into any JS environment
import { animate } from "popmotion";
react-motion is incompatible with modern React optimization patterns and causes excessive re-renders.
// react-motion: High re-render overhead
// Not compatible with React.memo optimizations effectively
Despite their differences, these libraries share core concepts for handling time-based state changes.
All libraries (except raw CSS) interpolate values between a start and end point. They convert time or physics steps into visual properties.
// Concept shared across all:
// Start Value -> [Engine] -> End Value
// 0 -> [Animation Logic] -> 100
Both framer-motion and react-spring (via config) allow custom easing to control acceleration curves, though react-spring simulates this via physics.
// framer-motion: Explicit easing
transition={{ ease: "circOut" }}
// react-spring: Simulated via friction/tension
config: { tension: 200, friction: 20 }
Modern libraries allow stopping animations mid-flight to prevent glitches when props change rapidly.
// framer-motion: Auto-cancels on prop change
// react-spring: Auto-updates spring target
// popmotion: stop() method available
| Feature | framer-motion | react-spring | popmotion | react-motion |
|---|---|---|---|---|
| Status | β Active | β Active | β Active | β Deprecated |
| Model | Keyframes (Default) | Physics (Springs) | Functional Loop | Physics (Springs) |
| Layout | Automatic (layout prop) | Manual (Measurements) | Manual (Custom) | Manual (Complex) |
| Gestures | Built-in (drag, whileTap) | Via @use-gesture | Manual Events | None |
| DX | High (Declarative) | Medium (Physics tuning) | Low (Imperative) | Low (Legacy) |
| Bundle | Moderate | Moderate | Small | Small (Legacy) |
framer-motion is the comprehensive toolkit π§°. It is the safest bet for most teams. It handles layout shifts, gestures, and sequencing with minimal code, letting developers focus on design rather than math. Use it for dashboards, marketing sites, and complex interactive UIs.
react-spring is the physics lab βοΈ. Choose it when you need specific physical behaviors that keyframes can't mimic, or if you are already invested in its ecosystem. It shines in data visualizations and organic UI feedback.
popmotion is the engine block ποΈ. Use it if you are building your own library, working outside React, or need a tiny, dependency-free animation primitive. It is powerful but requires more assembly.
react-motion is the museum piece ποΈ. It pioneered spring animations in React but is now obsolete. Do not start new projects with it.
Final Thought: For 90% of React projects, framer-motion offers the best balance of power and simplicity. Reserve react-spring for physics-heavy needs, and avoid react-motion entirely.
Choose framer-motion for most production React applications where you need a balance of ease-of-use, powerful features like layout animations and gesture recognition, and strong TypeScript support. It is the ideal default choice for teams wanting high-quality motion without managing physics configurations manually.
Use popmotion only if you are building a custom animation engine, working outside of React, or need fine-grained functional control over animation loops without the overhead of a component library. It is best suited for framework-agnostic projects or highly specialized use cases.
Do not choose react-motion for any new project. It is officially deprecated, suffers from performance issues due to its rendering model, and lacks modern features like layout projection. Existing projects should plan a migration to framer-motion or react-spring.
Select react-spring if your application relies heavily on complex, interdependent physics simulations or if you prefer tuning spring parameters (tension, friction) over fixed time durations. It excels in scenarios requiring natural, non-linear movement and offers a versatile API that works across React Native and web.
npm install motion
Motion is available for React, JavaScript and Vue.
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.
import { animate } from "motion"
animate("#box", { x: 100 })
Get started with JavaScript.
<script>
import { motion } from "motion-v"
</script>
<template> <motion.div :animate={{ x: 100 }} /> </template>
Get started with Motion for Vue.
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.
A one-time payment, lifetime-updates membership:
Motion is sustainable thanks to the kind support of its sponsors.
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.
Motion drives the animations on the Cursor homepage, and is working with Cursor to bring powerful AI workflows to the Motion examples and docs.