Motion (Framer Motion) React animation library. Use for drag-and-drop, scroll animations, gestures, SVG morphing, or encountering bundle size, complex transitions, spring physics errors.
/plugin marketplace add secondsky/claude-skills/plugin install motion@claude-skillsThis skill inherits all available tools. When active, it can use any tool Claude has access to.
references/accessibility-guide.mdreferences/common-patterns.mdreferences/core-concepts-deep-dive.mdreferences/motion-vs-auto-animate.mdreferences/nextjs-integration.mdreferences/performance-optimization.mdscripts/init-motion.shscripts/optimize-bundle.shtemplates/layout-transitions.tsxtemplates/motion-nextjs-client.tsxtemplates/motion-vite-basic.tsxtemplates/scroll-parallax.tsxtemplates/ui-components.tsxMotion (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:
Production Tested: React 19, Next.js 15, Vite 6, Tailwind v4
Complex Interactions:
Scroll-Based Animations:
Layout Transitions:
Advanced Features:
Bundle Optimization:
auto-animate instead: 3.28 KB vs 34 KB)framer-motion v12.23.24 workaround - see Known Issues)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
motion component: ~34 KB minified+gzippedLazyMotion + m component: ~4.6 KBuseAnimate mini: 2.3 KB (smallest React animation library)useAnimate hybrid: 17 KBmotion ComponentTransform 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 animationsNamed 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.
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:
key propsCommon 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>
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.
// 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.
<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.
<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.
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.
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 references/performance-optimization.md.
Respect prefers-reduced-motion:
import { MotionConfig } from "motion/react"
<MotionConfig reducedMotion="user">
<App />
</MotionConfig>
Keyboard Support: Use whileFocus for keyboard-triggered animations.
<motion.button whileFocus={{ scale: 1.1 }} tabIndex={0}>
Keyboard accessible
</motion.button>
For complete accessibility guide (ARIA patterns, screen readers, AnimatePresence workaround, testing), load references/accessibility-guide.md.
Modal Dialog (AnimatePresence + backdrop):
<AnimatePresence>
{isOpen && (
<motion.dialog exit={{ opacity: 0 }}>Content</motion.dialog>
)}
</AnimatePresence>
Accordion (height animation):
<motion.div animate={{ height: isOpen ? "auto" : 0 }}>
Content
</motion.div>
For 15+ production patterns (carousel, tabs, scroll reveal, parallax, notifications), load references/common-patterns.md.
Symptom: Components disappear instantly without exit animation.
Solution: AnimatePresence must stay mounted, wrap the conditional (not be wrapped by it):
// ❌ Wrong
{isVisible && <AnimatePresence><motion.div>Content</motion.div></AnimatePresence>}
// ✅ Correct
<AnimatePresence>
{isVisible && <motion.div key="unique">Content</motion.div>}
</AnimatePresence>
Symptom: Build fails with "motion is not defined" or SSR errors.
Solution: Add "use client" directive:
"use client"
import { motion } from "motion/react"
Symptom: Animations stutter or don't work.
Solution: Remove transition-* classes (Motion overrides CSS transitions):
// ❌ Wrong: <motion.div className="transition-all" animate={{ x: 100 }} />
// ✅ Correct: <motion.div animate={{ x: 100 }} />
Symptom: Wrangler build fails when using motion package.
Solution: Use framer-motion v12.23.24 instead (GitHub issue #2918):
bun add framer-motion # Same API, works with Workers
Symptom: 50-100+ animated items cause severe slowdown.
Solution: Use virtualization (react-window, react-virtuoso).
For 5+ additional issues (layoutScroll, layoutRoot, AnimatePresence + layoutId), load references/nextjs-integration.md or references/core-concepts-deep-dive.md.
Claude should load these references based on user needs:
references/core-concepts-deep-dive.md when:references/performance-optimization.md when:references/nextjs-integration.md when:references/accessibility-guide.md when:references/common-patterns.md when:references/motion-vs-auto-animate.md when:This skill includes 5 production-ready templates in the templates/ directory:
Copy templates into your project and customize as needed.
This skill includes 4 comprehensive reference guides:
See references/ directory for detailed guides.
This skill includes 2 automation scripts:
See scripts/ directory for automation tools.
Related Skills: auto-animate (simple lists), tailwind-v4-shadcn (styling), nextjs (App Router), cloudflare-worker-base
Motion vs AutoAnimate: Load references/motion-vs-auto-animate.md for detailed comparison.
Token Savings: ~83% (30k → 5k tokens) | Error Prevention: 100% (29+ errors) | Time Savings: ~85% (2-3 hrs → 20-30 min)
| Package | Version | Status |
|---|---|---|
| motion | 12.23.24 | ✅ Latest stable |
| framer-motion | 12.23.24 | ✅ Alternative for Cloudflare |
| react | 19.2.0 | ✅ Latest stable |
| vite | 6.0.0 | ✅ Latest stable |
Found an issue or have a suggestion?
Production Tested: ✅ React 19 + Next.js 15 + Vite 6 + Tailwind v4
Token Savings: ~83%
Error Prevention: 100% (29+ documented errors prevented)
Bundle Size: 2.3 KB (mini) - 34 KB (full), optimizable to 4.6 KB with LazyMotion
Accessibility: MotionConfig reducedMotion support
Ready to use! Install with ./scripts/install-skill.sh motion