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.2, Next.js 16.1, Vite 7.3, 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-animate skill instead:
- Todo list add/remove (auto-animate: 3.28 KB vs motion: 34 KB)
- Search results filtering
- Shopping cart items
- Notification toasts
- Basic accordions without gestures
Static Content:
- No user interaction or animations needed
- Server-rendered content without client interactivity
Cloudflare Workers Deployment β β
Fixed (Dec 2024):
- Previous build compatibility issues resolved (GitHub issue #2918 closed as completed)
- Motion now works directly with Wrangler - no workaround needed
- Both
motion and framer-motion v12.23.24 work correctly
3D Animations β Use dedicated 3D library:
- Three.js for WebGL
- React Three Fiber for React + Three.js
Installation
Latest Stable Version
pnpm add motion
npm install motion
yarn add motion
Current Version: 12.27.5 (verified 2026-01-21)
Note for Cloudflare Workers:
pnpm add motion
pnpm add framer-motion
Package Information
- Bundle Size:
- Full
motion component: ~34 KB minified+gzipped
LazyMotion + m component: ~4.6 KB
useAnimate mini: 2.3 KB (smallest React animation library)
useAnimate hybrid: 17 KB
- Dependencies: React 18+ or React 19+
- TypeScript: Native support included (no @types package needed)
Core Concepts
1. 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
key props
- AnimatePresence wraps the conditional, not the other way around
Common Mistake (exit animation won't play):
{isVisible && (
<AnimatePresence>
<motion.div>Content</motion.div>
</AnimatePresence>
)}
<AnimatePresence>
{isVisible && <motion.div key="unique">Content</motion.div>}
</AnimatePresence>
2. Layout Animations
Special Props:
layout: Enable FLIP layout animations
layoutId: Connect separate elements for shared transitions
layoutScroll: Fix animations in scrollable containers (see Issue #5)
layoutRoot: Fix animations in fixed-position elements (see Issue #7)
<motion.div layout>
{isExpanded ? <FullContent /> : <Summary />}
</motion.div>
3. Scroll Animations
Viewport-Triggered (whileInView)
<motion.div
initial={{ opacity: 0, y: 50 }}
whileInView={{ opacity: 1, y: 0 }}
viewport={{ once: true, margin: "-100px" }}
>
Fades in when 100px from entering viewport
</motion.div>
Scroll-Linked (useScroll)
import { useScroll, useTransform } from "motion/react"
const { scrollYProgress } = useScroll()
const y = useTransform(scrollYProgress, [0, 1], [0, -300])
<motion.div style={{ y }}>
Moves up 300px as user scrolls page
</motion.div>
Performance: Uses native ScrollTimeline API when available for hardware acceleration.
Integration Guides
Vite + React + TypeScript
pnpm add motion
Import: import { motion } from "motion/react"
No Vite configuration needed - works out of the box.
Next.js App Router (Recommended Pattern)
Key Requirement: Motion only works in Client Components (not Server Components).
Step 1: Create Client Component Wrapper
src/components/motion-client.tsx:
"use client"
import * as motion from "motion/react-client"
export { motion }
Step 2: Use in Server Components
src/app/page.tsx:
import { motion } from "@/components/motion-client"
export default function Page() {
return (
<motion.div
initial={{ opacity: 0 }}
animate={{ opacity: 1 }}
>
This works in Server Component (wrapper is client)
</motion.div>
)
}
Alternative: Direct Client Component