Framer Motion: A Complete Guide for React & Next.js Developers
Framer Motion is the de facto animation library for React in 2026. This guide covers installation, the declarative motion API, variants, layout animations, gestures, scroll animations, and production best practices โ with runnable examples throughout.
Full-stack web developer with hands-on production experience in React, Next.js, Node.js, PostgreSQL, and Prisma. Founder of ToolsWaves โ a privacy-first toolkit of 35+ free developer and design utilities. I write every tutorial from real shipping experience, focusing on performance, scalable architecture, and clean, type-safe code.

Prototype CSS animations with our free generator
CSS Animation Generator
What is Framer Motion?
Framer Motion is an open-source animation library for React that makes creating high-performance animations incredibly simple. Instead of manipulating CSS classes, writing @keyframes rules, or using imperative JavaScript to drive animations, developers describe animations declaratively as props on React components. The library takes care of interpolation, GPU acceleration, gesture handling, and lifecycle management.
The core idea is a family of motion.* components that wrap standard HTML and SVG elements โ <motion.div>, <motion.button>, <motion.img>, and so on. Each motion component accepts animation props (initial, animate, exit, transition, whileHover, whileTap, drag, layout) that describe how the element should behave. A single fade-in becomes a three-line declaration:
import { motion } from "framer-motion";
export default function App() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.6 }}
>
Hello World
</motion.div>
);
}With those few lines you have created a smooth fade-in animation. There is no useEffect, no ref, no CSS keyframes file, and no state management. This is the design pattern Framer Motion is built around, and it scales from tiny micro-interactions to full page transitions without changing shape.
Why Choose Framer Motion?
Five properties make Framer Motion the default choice for React animation in 2026:
1. Simple, Declarative API
Animations are defined as props instead of imperative JavaScript. `whileHover={{ scale: 1.1 }}` on a button, and Framer Motion handles the whole hover-scale interaction โ timing, easing, cancel behavior on mouseout, everything. Compare that to the equivalent CSS + JavaScript combination and the ergonomic win is obvious.
2. Excellent Performance
Framer Motion uses GPU-accelerated transforms whenever possible, resulting in smooth 60 FPS animations even in complex interfaces. It intelligently uses transform and opacity (properties the browser can composite on the GPU) instead of layout properties that trigger expensive layout and paint passes.
3. Perfect for React
Since it is built specifically for React, animations integrate naturally with state, props, and component lifecycles. Conditional rendering of animated components works out of the box. Animations react to prop changes automatically. This is a genuinely different experience from bolt-on animation libraries that treat React as an afterthought.
4. Layout Animations
Animating changing layouts becomes almost effortless with the `layout` prop. Framer Motion measures the element's position before and after the layout change (via FLIP โ First, Last, Invert, Play technique) and animates smoothly between them. Useful for filtering lists, expanding/collapsing cards, and drag-to-reorder interfaces.
5. Built-in Gesture Support
Hover, tap, drag, pan, focus, and scroll gestures are supported through dedicated props with no additional libraries. Drag with `drag`, tap animation with `whileTap`, scroll-triggered entrance with `whileInView`. Everything you need for modern interactive UIs is built in.
Installation
Framer Motion is a standard npm package with no build-time configuration required. Install using your preferred package manager:
# npm
npm install framer-motion
# yarn
yarn add framer-motion
# pnpm
pnpm add framer-motionImport motion components from `framer-motion` at the top of any file where you want to use animations. In Next.js App Router projects, files that import motion.* components must be client components โ add `"use client"` at the top. This is because motion components rely on browser APIs (measuring elements, listening to gestures) that do not exist in a Node.js server-rendering context.
Core Concepts
Six props do 90% of the animation work in Framer Motion. Learn these and you can build almost any animation you need:
initial
The starting values before the animation begins. `initial={{ opacity: 0, y: 50 }}` means the element starts invisible and 50px below its final position. If you want an element to appear at its natural state without an entrance animation, pass `initial={false}`.
animate
The target values Framer Motion animates toward. `animate={{ opacity: 1, y: 0 }}` reveals the element to its final position. When the values in animate change (e.g., driven by state), the animation runs again toward the new target.
exit
The animation to play when the component is removed from the tree. Only works when the component is wrapped in `<AnimatePresence>`, which lets Framer Motion delay the actual unmount until the exit animation completes. Essential for modals, dialogs, and page transitions.
transition
Controls timing โ duration, easing, delay, stagger, spring configuration. `transition={{ duration: 0.5, ease: "easeOut" }}` for classic timed animations, or `transition={{ type: "spring", stiffness: 300 }}` for spring physics.
whileHover / whileTap / whileFocus / whileInView
Conditional animation states triggered by user interaction or viewport entry. `whileHover={{ scale: 1.1 }}` grows the element on hover. `whileInView={{ opacity: 1 }}` fades in when scrolled into view. These are massive time-savers vs implementing the equivalent with CSS + JavaScript state.
layout
`layout` (boolean or a layoutId string) tells Framer Motion to animate any layout changes that happen to this element โ position, size, or grid placement. Useful for accordion panels, sortable lists, and shared-element transitions between routes.
Practical Examples
The examples below cover the animations you will build 90% of the time in a real application:
// Fade in
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
transition={{ duration: 0.5 }}
/>
// Slide up on mount
<motion.div
initial={{ y: 100, opacity: 0 }}
animate={{ y: 0, opacity: 1 }}
transition={{ duration: 0.7 }}
/>
// Scale on hover
<motion.div whileHover={{ scale: 1.1 }} />
// Continuous rotation
<motion.div
animate={{ rotate: 360 }}
transition={{ duration: 2, repeat: Infinity, ease: "linear" }}
/>
// Drag with constraints
<motion.div drag dragConstraints={{ left: -100, right: 100 }} />Every one of these examples is production-ready โ drop them into any React component and they work. There is no setup step, no configuration, no CSS class management. This is what people mean when they say Framer Motion has a great developer experience: the code you write matches the animation you want.
Animating Lists with AnimatePresence
Lists that add and remove items are one of the most common places you want animation, and they are also one of the trickiest to get right. Framer Motion's <AnimatePresence> component makes this straightforward:
import { motion, AnimatePresence } from "framer-motion";
<AnimatePresence>
{items.map((item) => (
<motion.div
key={item.id}
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -20 }}
transition={{ duration: 0.2 }}
>
{item.name}
</motion.div>
))}
</AnimatePresence>AnimatePresence tracks which children are mounting and unmounting. When you filter a list, remove an item, or add a new entry, AnimatePresence keeps the removed items in the DOM long enough for their exit animation to play, then unmounts them. Without it, React unmounts removed children instantly and exit animations never fire.
Scroll-Based Animations
Landing pages, portfolios, and marketing sites benefit enormously from scroll-triggered animations โ sections fading in as the user scrolls, images sliding into place, text revealing progressively. Framer Motion's `whileInView` handles the common case in one line:
<motion.div
initial={{ opacity: 0, y: 40 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, amount: 0.3 }}
transition={{ duration: 0.6 }}
>
This slides in when 30% of it enters the viewport, and only once.
</motion.div>The `viewport` prop controls when the animation triggers. `once: true` ensures the animation only plays the first time the element enters view (not every scroll pass). `amount: 0.3` requires 30% of the element to be visible before triggering โ useful for elements taller than the viewport itself.
Variants โ Reusable Animation Definitions
For anything beyond the smallest animations, you want to define the animation once and reuse it. Variants are Framer Motion's answer:
const container = {
hidden: { opacity: 0 },
visible: {
opacity: 1,
transition: { staggerChildren: 0.1 },
},
};
const item = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 },
};
<motion.ul variants={container} initial="hidden" animate="visible">
{items.map((i) => (
<motion.li key={i.id} variants={item}>{i.name}</motion.li>
))}
</motion.ul>This pattern is powerful for two reasons. First, variants are declared once and reused, keeping animation code DRY. Second, `staggerChildren` propagates animation state through the tree with a delay between siblings โ the parent's transition to 'visible' triggers each child's transition to 'visible' with a 100ms stagger, producing a classic cascade effect without extra plumbing.
Integrating with Next.js
Framer Motion works seamlessly with Next.js โ both the older Pages Router and the modern App Router. In the App Router, any component using motion.* imports must be marked `"use client"` because motion primitives depend on browser APIs.
Common Next.js use cases: page transitions with AnimatePresence at the layout level, animated route change indicators, hero-section entrance animations on marketing pages, animated navigation menus, card grids with staggered reveals, image gallery modals with shared-element transitions between grid and full-screen views. Server Components can render animated Client Components โ the client boundary just needs to be at the animated component level.
Best Practices for Production
The difference between Framer Motion animations that feel amazing and animations that feel amateur is discipline about six practices:
- Animate transform and opacity, not layout properties โ width, height, top, left force layout on every frame. transform and opacity are GPU-composited and stay smooth under load.
- Keep durations between 200-600ms for most UI interactions. Faster feels rushed and jittery; slower feels sluggish. Reserve longer animations for hero moments and page transitions.
- Use spring animations for natural movement โ `transition={{ type: "spring", stiffness: 300, damping: 30 }}` feels more physical than any easing curve for interactive elements. Reserve linear/eased timing for progress bars and non-interactive animations.
- Avoid animating large numbers of DOM nodes simultaneously. Staggered animations are fine; 200 nodes all animating at once is not. If you must, disable animations on lower-end devices via the `useReducedMotion` hook.
- Respect prefers-reduced-motion โ users with vestibular disorders experience nausea from motion. Framer Motion exposes `useReducedMotion()` hook; return early or use minimal animations when true.
- Reuse animation variants across the app for consistency. A design system with 5 canonical entrance animations feels more polished than 50 one-off animations with subtly different timings.
When Should You Use Framer Motion?
Framer Motion is an excellent choice for React and Next.js applications that need any of:
- SaaS dashboards with subtle state-change motion
- Business websites with polished entrance animations
- Landing pages with scroll-triggered reveals
- Portfolio websites with interactive galleries
- E-commerce stores with animated product interactions
- Marketing sites with hero animations and page transitions
- Interactive product demos and case-study pages
- Startup websites that want to feel premium from day one
It is genuinely overkill for content-heavy sites where users scroll and read (Wikipedia does not need motion), or for tools where every millisecond matters and animations get in the way of the workflow. But for anything user-facing where perceived quality matters, Framer Motion is a positive-ROI dependency.
Pros and Cons
Nothing is perfect. Where Framer Motion wins and where it doesn't:
Pros
Easy to learn โ the declarative API matches how React developers already think. Excellent React integration โ hooks, refs, and state work seamlessly. Great performance โ GPU-composited transforms stay smooth. Powerful gesture support โ hover, drag, tap, pan, scroll built in. Layout animations via FLIP โ hard to build from scratch. Active community and ecosystem. First-class TypeScript support. Works cleanly with Next.js.
Cons
React-only โ you cannot reuse animations across other frameworks. Bundle size is larger than pure CSS animations (~30KB gzipped) โ meaningful for landing pages where every byte counts. Advanced animation orchestration (multi-stage sequences, complex scroll-linked animations) has a learning curve. For very simple hover/transition effects, CSS may be lighter and simpler.
Final Thoughts
Framer Motion has become the go-to animation library for modern React development because it strikes the perfect balance between simplicity and power. Whether you are building subtle micro-interactions on a dashboard or sophisticated page transitions on a marketing site, it helps you ship polished, delightful user experiences with minimal code. The declarative API is teachable in an afternoon; the depth of the library reveals itself as your needs grow. If you are starting a new React or Next.js project in 2026 and animations are anywhere on your feature list, Framer Motion is one of the first dependencies worth adding.
Open Animation Generator โFrequently Asked Questions
Is Framer Motion free?
Yes. Framer Motion is open source under the MIT license and free to use in any project, personal or commercial. No paid tier or license fee.
Does Framer Motion work with Next.js?
Absolutely. It integrates seamlessly with both the Pages Router and the App Router. In the App Router, files using motion.* components must be marked `"use client"` because motion primitives require browser APIs. Server components can render animated client components โ the client boundary is just at the animated component level.
Is Framer Motion better than CSS animations?
For simple effects (hover states, static keyframes), CSS is lighter and simpler. For interactive, state-driven, and complex UI animations โ entrance/exit animations tied to component lifecycle, gestures, layout changes, scroll-triggered motion โ Framer Motion offers dramatically better developer productivity. Use both: CSS for static effects, Framer Motion for interactive motion.
Can I use Framer Motion with TypeScript?
Yes. Framer Motion ships first-class TypeScript definitions. All motion props, variants, and hooks are strictly typed, which prevents an entire category of animation bugs at compile time.
How large is Framer Motion's bundle?
Approximately 30-50KB gzipped for the full library. This is meaningful on a marketing page where every byte counts, negligible on a SaaS dashboard. If bundle size is critical, tree-shaking removes unused parts of the library; you only pay for the motion features you import.
How does Framer Motion compare to React Spring?
React Spring uses spring physics as its primary paradigm; Framer Motion supports both spring physics and traditional easing. Framer Motion has broader features (gestures, layout animations, AnimatePresence) and larger community adoption. React Spring is smaller and more focused. For most projects Framer Motion wins on feature breadth; React Spring wins on bundle size when you only need spring animations.
Related Articles

Animate UI โ Animated React Components for Modern Web Applications
Modern users expect interfaces that feel smooth, responsive, and visually engaging โ but managing complex animation logic slows every team down. Animate UI is the React component library that ships polished animations by default, so developers can focus on features.

Mastering Caching in Next.js: Request Memoization, Data Cache, Route Cache & Router Cache
Next.js ships with four distinct caching layers โ and most developers never touch three of them. Get them right and pages load instantly; get them wrong and you serve stale data or hammer your APIs. Here is the practical playbook.

Next.js Server Actions: A Practical Guide to Data Mutations Without APIs
Server Actions killed the boilerplate of building custom API routes for every form or mutation. But the ergonomics come with pitfalls โ misuse them and you get slow forms, security holes, or broken progressive enhancement. Here is the practical playbook.