Motion Animation Library
Overview
Motion (package: motion, formerly framer-motion) is the industry-standard React animation library used in production by thousands of applications. With 30,200+ GitHub stars and 300+ official examples, it provides a declarative API for creating sophisticated animations with minimal code.
Key Capabilities:
- Gestures: drag, hover, tap, pan, focus with cross-device support
- Scroll Animations: viewport-triggered, scroll-linked, parallax effects
- Layout Animations: FLIP technique for smooth layout changes, shared element transitions
- Spring Physics: Natural, customizable motion with physics-based easing
- SVG: Path morphing, line drawing, attribute animation
- Exit Animations: AnimatePresence for unmounting transitions
- Performance: Hardware-accelerated, ScrollTimeline API, bundle optimization (2.3 KB - 34 KB)
Production Tested: React 19, Next.js 15, Vite 6, Tailwind v4
When to Use This Skill
✅ Use Motion When:
Complex Interactions:
- Drag-and-drop interfaces (sortable lists, kanban boards, sliders)
- Hover states with scale/rotation/color changes
- Tap feedback with bounce/squeeze effects
- Pan gestures for mobile-friendly controls
Scroll-Based Animations:
- Hero sections with parallax layers
- Scroll-triggered reveals (fade in as elements enter viewport)
- Progress bars linked to scroll position
- Sticky headers with scroll-dependent transforms
Layout Transitions:
- Shared element transitions between routes (card → detail page)
- Expand/collapse with automatic height animation
- Grid/list view switching with smooth repositioning
- Tab navigation with animated underline
Advanced Features:
- SVG line drawing animations
- Path morphing between shapes
- Spring physics for natural bounce
- Orchestrated sequences (staggered reveals)
- Modal dialogs with backdrop blur
Bundle Optimization:
- Need 2.3 KB animation library (useAnimate mini)
- Want to reduce Motion from 34 KB to 4.6 KB (LazyMotion)
❌ Don't Use Motion When:
- Simple list animations (use
auto-animateinstead: 3.28 KB vs 34 KB) - Static content without interactions
- Cloudflare Workers (use
framer-motionv12.23.24 workaround - see Known Issues) - 3D animations (use Three.js or React Three Fiber instead)
Installation
Latest Stable Version
bun add motion # preferred
# or: npm install motion
# or: yarn add motion
Current Version: 12.23.24 (verified 2025-11-07)
Alternative for Cloudflare Workers:
# Use framer-motion if deploying to Cloudflare Workers
bun add framer-motion
# or: npm install framer-motion
Package Information
- Bundle Size:
- Full
motioncomponent: ~34 KB minified+gzipped LazyMotion+mcomponent: ~4.6 KBuseAnimatemini: 2.3 KB (smallest React animation library)useAnimatehybrid: 17 KB- Dependencies: React 18+ or React 19+
- TypeScript: Native support included (no @types package needed)
Core Concepts
1. The motion Component
Transform any HTML/SVG element into an animatable component:
import { motion } from "motion/react"
// Basic animation
<motion.div
initial={{ opacity: 0, y: 20 }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: 0.5 }}
>
Content fades in and slides up
</motion.div>
// Gesture controls
<motion.button
whileHover={{ scale: 1.1 }}
whileTap={{ scale: 0.95 }}
>
Click me
</motion.button>
Props:
initial: Starting state (object or variant name)animate: Target state (object or variant name)exit: Unmounting state (requires AnimatePresence)transition: Timing/easing configurationwhileHover,whileTap,whileFocus: Gesture stateswhileInView: Viewport-triggered animationdrag: Enable dragging ("x", "y", or true for both)layout: Enable FLIP layout animations
2. Variants (Animation Orchestration)
Named animation states that propagate through component tree:
const variants = {
hidden: { opacity: 0, y: 20 },
visible: { opacity: 1, y: 0 }
}
<motion.div variants={variants} initial="hidden" animate="visible">
Content
</motion.div>
For advanced orchestration (staggerChildren, delayChildren, dynamic variants), load references/core-concepts-deep-dive.md.
3. AnimatePresence (Exit Animations)
Enables animations when components unmount:
import { AnimatePresence } from "motion/react"
<AnimatePresence>
{isVisible && (
<motion.div
key="modal"
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
exit={{ opacity: 0 }}
>
Modal content
</motion.div>
)}
</AnimatePresence>
Critical Rules:
- AnimatePresence must stay mounted (don't wrap in conditional)
- All children must have unique
keyprops - AnimatePresence wraps the conditional, not the other way around
Common Mistake (exit animation won't play):
// ❌ Wrong - AnimatePresence unmounts with condition
{isVisible && (
<AnimatePresence>
<motion.div>Content</motion.div>
</AnimatePresence>
)}
// ✅ Correct - AnimatePresence stays mounted
<AnimatePresence>
{isVisible && <motion.div key="unique">Content</motion.div>}
</AnimatePresence>
4. Layout Animations (FLIP)
Automatically animate layout changes:
<motion.div layout>
{isExpanded ? <FullContent /> : <Summary />}
</motion.div>
Special props: layoutId (shared element transitions), layoutScroll (scrollable containers), layoutRoot (fixed positioning).
For advanced patterns (LayoutGroup, layoutId orchestration), load references/core-concepts-deep-dive.md.
5. Scroll Animations
// Viewport-triggered
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true }}
>
Fades in when entering viewport
</motion.div>
// Scroll-linked (parallax)
import { useScroll, useTransform } from "motion/react"
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
<motion.div style={{ y }}>Parallax effect</motion.div>
For advanced scroll patterns (useScroll offsets, useTransform easing, parallax layers), load references/core-concepts-deep-dive.md.
6. Gestures
<motion.div drag="x" dragConstraints={{ left: -200, right: 200 }}>
Drag me
</motion.div>
Available: whileHover, whileTap, whileFocus, whileDrag, whileInView, drag.
For advanced drag controls (momentum, elastic, event handlers), load references/core-concepts-deep-dive.md.
7. Spring Physics
<motion.div
animate={{ x: 100 }}
transition={{ type: "spring", stiffness: 100, damping: 10 }}
/>
Common presets: Bouncy { stiffness: 300, damping: 10 }, Smooth { stiffness: 100, damping: 20 }.
For spring tuning (mass, visualizer, presets), load references/core-concepts-deep-dive.md.
Integration Guides
Vite: bun add motion → import { motion } from "motion/react" (works out of the box)
Next.js App Router: Requires "use client" directive or client component wrapper
"use client"
import { motion } from "motion/react"
Tailwind: ⚠️ Remove transition-* classes (causes conflicts with Motion animations)
Cloudflare Workers: Use framer-motion v12.23.24 instead (Motion has Wrangler build issues)
For complete integration guides (Next.js patterns, SSR, framework-specific issues), load references/nextjs-integration.md.
Performance Optimization
Bundle Size: Use LazyMotion (34 KB → 4.6 KB):
import { LazyMotion, domAnimation, m } from "motion/react"
<LazyMotion features={domAnimation}>
<m.div>Only 4.6 KB!</m.div>
</LazyMotion>
Large Lists: Use virtualization (react-window, react-virtuoso) for 50+ animated items.
For complete optimization guide (hardware acceleration, memory profiling, production benchmarks), load `