Motion Animation Patterns
Quick Guide: Use Motion for declarative React animations.
motion.*components for basic animations, variants for orchestrated sequences, AnimatePresence for exit animations,layout/layoutIdfor FLIP animations,useScroll/useInViewfor scroll-triggered effects. Always animate transform properties (x, y, scale, rotate, opacity) for GPU performance. Always respect reduced motion viaMotionConfig reducedMotion="user".
Import:
import { motion } from "motion/react"(v11+ package rename fromframer-motion)
<critical_requirements>
CRITICAL: Before Using This Skill
All code must follow project conventions in CLAUDE.md (kebab-case, named exports, import ordering,
import type, named constants)
(You MUST wrap exiting components in AnimatePresence for exit animations to work)
(You MUST provide unique key prop to direct children of AnimatePresence)
(You MUST animate transform properties (x, y, scale, rotate, opacity) for GPU-accelerated performance)
(You MUST respect reduced motion preferences using MotionConfig or useReducedMotion)
(You MUST use named constants for all animation timing values - NO magic numbers)
</critical_requirements>
Auto-detection: Motion, Framer Motion, motion.div, motion.button, AnimatePresence, useAnimation, useScroll, useInView, usePageInView, variants, whileHover, whileTap, layoutId, spring, tween, stagger, "motion/react", "framer-motion"
When to use:
- Animating component enter/exit/presence
- Orchestrating complex multi-element animations with variants
- Implementing gesture-based interactions (hover, tap, drag)
- Creating scroll-triggered or scroll-linked animations
- Animating layout changes and shared element transitions
- Building micro-interactions and UI feedback
When NOT to use:
- Simple CSS transitions (use CSS transitions instead)
- Complex timeline-based animations requiring frame-level control (consider a dedicated timeline animation library)
- Performance-critical animations on low-powered devices without careful optimization
Key patterns covered:
- motion components and animation props (initial, animate, exit, transition)
- Variants for reusable, orchestrated animations
- AnimatePresence for exit animations and animation modes
- Gesture props (whileHover, whileTap, whileDrag, drag)
- Layout animations (layout prop, layoutId, LayoutGroup)
- Scroll animations (useScroll, useInView, whileInView)
- Spring and tween transitions
- useAnimation for imperative control
- Reduced motion accessibility
- v12: usePageInView, enhanced stagger(), drag stop/cancel
Detailed Resources:
- examples/core.md - Motion components, variants, AnimatePresence, gestures, accessibility
- examples/layout.md - Layout animations, shared elements, expandable cards
- examples/scroll.md - Scroll progress, reveal, parallax
- examples/sequences.md - Complex sequences, keyframes
- examples/svg.md - SVG path animations
- reference.md - Decision frameworks, migration guide, anti-patterns, performance, quick reference
<philosophy>
Philosophy
Motion is a declarative animation library for React that makes animations feel natural and accessible. It uses a physics-based approach with spring animations as defaults, creating fluid motion that matches real-world expectations.
Core principles:
- Declarative over imperative - Describe what the animation should look like, not how to achieve it
- Props over keyframes - Use
initial,animate,exitprops instead of CSS keyframes - Variants for orchestration - Group related animations and control timing with parent-child relationships
- Performance through transforms - Animate GPU-accelerated properties (transform, opacity) for smooth 60fps
- Accessibility built-in - Respect user preferences for reduced motion
<patterns>
Core Patterns
Pattern 1: Basic Motion Components
Prefix any HTML or SVG element with motion. to make it animatable. Use initial, animate, exit, and transition props.
import { motion } from "motion/react";
const FADE_DURATION_S = 0.3;
const SLIDE_DISTANCE_PX = 20;
export const FadeIn = ({ children }: { children: React.ReactNode }) => (
<motion.div
initial={{ opacity: 0, y: SLIDE_DISTANCE_PX }}
animate={{ opacity: 1, y: 0 }}
transition={{ duration: FADE_DURATION_S }}
>
{children}
</motion.div>
);
Why good: Named constants, declarative intent, y is GPU-accelerated (never animate top/left/margin)
See examples/core.md Pattern 1 for full examples with className, delay props, and bad examples.
Pattern 2: Variants for Orchestrated Animations
Variants define reusable animation states and enable parent-child orchestration with staggerChildren.
import { motion, type Variants } from "motion/react";
const STAGGER_DELAY_S = 0.1;
const ITEM_DISTANCE_PX = 20;
const containerVariants: Variants = {
hidden: { opacity: 0 },
visible: { opacity: 1, transition: { staggerChildren: STAGGER_DELAY_S } },
};
const itemVariants: Variants = {
hidden: { opacity: 0, y: ITEM_DISTANCE_PX },
visible: { opacity: 1, y: 0 },
};
Children automatically inherit animation state from parent. Use staggerDirection: -1 for reverse stagger on exit.
See examples/core.md Pattern 2 for complete list animation with exit variants.
Pattern 3: AnimatePresence for Exit Animations
AnimatePresence enables exit animations for components being removed from the React tree. Direct children must have unique key props.
import { AnimatePresence, motion } from "motion/react";
const MODAL_SCALE_HIDDEN = 0.95;
<AnimatePresence>
{isOpen && (
<motion.div
key="modal"
initial={{ opacity: 0, scale: MODAL_SCALE_HIDDEN }}
animate={{ opacity: 1, scale: 1 }}
exit={{ opacity: 0, scale: MODAL_SCALE_HIDDEN }}
/>
)}
</AnimatePresence>
Animation modes: mode="sync" (default, simultaneous), mode="wait" (wait for exit before enter - ideal for page transitions), mode="popLayout" (for shared layout transitions).
See examples/core.md Pattern 3 for modal and page transition examples.
Pattern 4: Gesture Animations
Gesture props enable hover, tap, focus, and drag interactions.
const HOVER_SCALE = 1.05;
const TAP_SCALE = 0.95;
const GESTURE_SPRING = { type: "spring" as const, stiffness: 400, damping: 17 };
<motion.button
whileHover={{ scale: HOVER_SCALE }}
whileTap={{ scale: TAP_SCALE }}
transition={GESTURE_SPRING}
/>
For drag: use drag, dragConstraints, dragElastic, whileDrag. Use useDragControls for programmatic drag (v12+ adds .stop()/.cancel()).
See examples/core.md Pattern 4 for interactive card and draggable element examples.
Pattern 5: Layout Animations
The layout prop animates layout changes automatically using FLIP technique. Use layout="position" on children to prevent text distortion. Use layoutId for shared element transitions across different containers.
<motion.div layout transition={LAYOUT_SPRING}>
<motion.h2 layout="position">Title</motion.h2>
</motion.div>
// Shared element: layoutId creates seamless transitions
{activeTab === tab && <motion.div layoutId="indicator" />}
Use LayoutGroup with id prop to scope layoutId to component instances (layoutId is global by default).
See examples/layout.md for expandable cards and tab indicator examples.
Pattern 6: Scroll-Triggered Animations
whileInView for scroll-triggered animations. useScroll + useTransform for scroll-linked effects.
const REVEAL_DISTANCE_PX = 50;
const PAR