Advanced Framer Motion
Framer Motion (now known as Motion for React) is the production-grade animation library for React that goes far beyond simple transitions. While most developers are familiar with its basic animate and transition props, advanced Framer Motion unlocks a powerful toolkit: layout animations, gesture-driven interactions, orchestration, and low-level MotionValues for fine-grained control.
This course section dives deep into the advanced APIs — useMotionValue, useTransform, useScroll, layoutId, AnimatePresence, and orchestration patterns — that separate amateur animations from polished, professional interfaces.
The core mental model: every animation in Framer Motion is driven by values. The declarative animate prop is syntactic sugar over the imperative MotionValue system underneath.
At the advanced level, you'll learn to combine all three branches of this architecture to build animation systems that are performant, composable, and delightful.
5 Advanced Framer Motion Techniques I Shouldn't Have Skipped
1. MotionValues — The Reactive Primitives
A MotionValue is the fundamental building block of every Framer Motion animation. When you write animate={{ x: 100 }}, Framer Motion creates a MotionValue internally to track x.
Why Use MotionValues Directly?
- Avoid re-renders: MotionValues update outside React's render cycle, making them ideal for scroll-linked or drag-linked animations where 60fps updates would otherwise trigger 60 re-renders per second.
- Compose and transform: Chain values together with
useTransformto create derived values without React state. - Read imperatively: Access
.get()/.set()for programmatic control.
| Approach | Re-renders | Best For |
|---|---|---|
animate prop | Yes (state-driven) | Simple mount/exit animations |
variants | Triggered only | Multi-property orchestrated sequences |
| MotionValues | No | Scroll, drag, gesture, continuous tracking |
useAnimate | Minimal | Timeline-driven imperative sequences |
Creating and Using MotionValues
The useMotionValue(initial) hook initializes a value, and you bind it to a component via the style prop:
1import { motion, useMotionValue } from "framer-motion"; 2 3function DraggableBox() { 4 const x = useMotionValue(0); 5 const scale = useMotionValue(1); 6 7 return ( 8 <motion.div 9 drag="x" 10 style={{ x, scale }} 11 onDrag={() => scale.set(1.1)} 12 onDragEnd={() => scale.set(1)} 13 /> 14 ); 15}
The
dragprop automatically updates thexMotionValue, and sincescaleis also a MotionValue, the scale transition happens without any re-render.
Performance: MotionValues vs State
Always prefer useMotionValue over useState for values that change every frame (scroll position, drag coordinates, pointer tracking). A useState update triggers a full React re-render on every frame — a MotionValue update just changes a style property directly through the animation engine, bypassing React entirely.
2. Value Transformation with useTransform
useTransform creates a derived MotionValue — it maps the output of one MotionValue through a transformation function or a range mapping. This is the compositional superpower of Framer Motion.
Range Mapping Syntax
The most common pattern is mapping input ranges to output ranges:
Where the mapping is defined by corresponding input/output range pairs:
1import { useScroll, useTransform, motion } from "framer-motion"; 2 3function ParallaxSection() { 4 const { scrollYProgress } = useScroll(); 5 const y = useTransform(scrollYProgress, [0, 1], [0, -200]); 6 const opacity = useTransform(scrollYProgress, [0, 0.5], [1, 0]); 7 8 return ( 9 <motion.div style={{ y, opacity }}> 10 This content parallax-scrolls and fades. 11 </motion.div> 12 ); 13}
| Param | Type | Description |
|---|---|---|
value | MotionValue | The source value to transform |
inputRange | number[] | Monotonically increasing input values |
outputRange | number[] | string[] | Corresponding output values (supports colors, px, deg) |
options.clamp | boolean | Whether to clamp output beyond range (default: true) |
Function Transformer
You can also pass a function for non-linear mappings:
1const rotate = useTransform(x, (latestX) => latestX * 0.5); 2const color = useTransform( 3 dragDistance, 4 (d) => (d > 100 ? "#ff4444" : "#44aaff") 5);
Chaining Transforms
Since useTransform returns a MotionValue, you can chain them:
Building a Scroll-Linked Parallax Animation
- 1Step 1
Use
useScroll()to obtain ascrollYProgressMotionValue. Optionally pass atargetref andoffsetarray to track a specific element entering/exiting the viewport.1const { scrollYProgress } = useScroll({ 2 target: sectionRef, 3 offset: ['start end', 'end start'] 4}); - 2Step 2
Create as many derived MotionValues as needed using
useTransform. Each maps a different range of the scroll progress to a specific animation property.1const y = useTransform(scrollYProgress, [0, 1], [100, -100]); 2const scale = useTransform(scrollYProgress, [0, 0.5, 1], [0.8, 1, 0.8]); 3const rotate = useTransform(scrollYProgress, [0, 1], [0, 360]); - 3Step 3
Pass the derived MotionValues to
motion.*elements via thestyleprop. MotionValues bypass React's render cycle, so these update at 60fps without re-renders.1<motion.div style={{ y, scale, rotate }}> 2 Parallax Content 3</motion.div> - 4Step 4
For scroll-smoothing effects, wrap raw MotionValues with
useSpringto add physics-based interpolation. This prevents janky linear scroll mapping.1import { useSpring } from 'framer-motion'; 2const smoothY = useSpring(y, { stiffness: 100, damping: 30 }); - 5Step 5
Create depth by applying different parallax rates to different layers. Backgrounds move slower (smaller range), foregrounds move faster (larger range). This creates a convincing parallax effect.
1const bgY = useTransform(scrollYProgress, [0,1], [0, -50]); 2const fgY = useTransform(scrollYProgress, [0,1], [0, -200]);
3. Advanced Orchestration with Variants
Variants allow you to define named animation states and propagate them through the motion component tree. This is the primary tool for orchestrating complex, multi-element sequences.
The Inheritance Model
When a parent changes its animate prop, all descendant motion components receive the same variant label. This means you only need to toggle the parent to orchestrate the entire tree.
Staggered Children with staggerChildren
The staggerChildren transition option delays each child's animation relative to its predecessor:
1const container = { 2 hidden: { opacity: 0 }, 3 visible: { 4 opacity: 1, 5 transition: { 6 staggerChildren: 0.08, 7 delayChildren: 0.2, 8 }, 9 }, 10}; 11 12const item = { 13 hidden: { y: 20, opacity: 0 }, 14 visible: { y: 0, opacity: 1 }, 15}; 16 17function StaggeredList({ items }) { 18 return ( 19 <motion.ul 20 variants={container} 21 initial="hidden" 22 animate="visible" 23 > 24 {items.map((text, i) => ( 25 <motion.li key={i} variants={item}> 26 {text} 27 </motion.li> 28 ))} 29 </motion.ul> 30 ); 31}
Dynamic Variants
Variants can be functions that receive custom data, allowing per-item customization:
1const item = { 2 hidden: (custom) => ({ 3 opacity: 0, 4 y: custom * 100, 5 }), 6 visible: (custom) => ({ 7 opacity: 1, 8 y: 0, 9 transition: { delay: custom * 0.1 }, 10 }), 11}; 12 13// Usage: pass custom prop to each child 14<motion.li custom={index} variants={item} />
Variant Propagation Gotcha
Non-motion components break the propagation chain. If you have a <div> between a parent motion.ul and child motion.li, the variant signal will NOT reach the children. Always use motion.* components for every element in the tree that needs to participate in the orchestration.
4. Layout Animations & Shared Layout Transitions
Layout animations are one of Framer Motion's most powerful features. They automatically animate an element from its old position/size to its new one when the DOM layout changes, using a technique inspired by FLIP.
The layout Prop
Simply add layout to any motion.* component. When React re-renders and the element's position or size changes, it animates smoothly:
1function ToggleGrid() { 2 const [isExpanded, setIsExpanded] = useState(false); 3 4 return ( 5 <motion.div 6 layout 7 style={{ 8 width: isExpanded ? "100%" : "50%", 9 }} 10 onClick={() => setIsExpanded(!isExpanded)} 11 /> 12 ); 13}
Shared Layout with layoutId
When two motion components share the same layoutId in different parts of the tree, Framer Motion automatically animates between them — even across route changes with AnimatePresence:
1function CardToModal() { 2 const [selected, setSelected] = useState(null); 3 4 return ( 5 <> 6 {items.map((item) => ( 7 <motion.div 8 layoutId={`card-${item.id}`} 9 onClick={() => setSelected(item)} 10 > 11 <motion.img layoutId={`image-${item.id}`} src={item.src} /> 12 <p>{item.title}</p> 13 </motion.div> 14 ))} 15 16 <AnimatePresence> 17 {selected && ( 18 <motion.div layoutId={`card-${selected.id}`}> 19 <motion.img layoutId={`image-${selected.id}`} /> 20 <p>{selected.body}</p> 21 </motion.div> 22 )} 23 </AnimatePresence> 24 </> 25 ); 26}
layoutDependency and layoutScope
Controlling when layout animations trigger is critical for performance:
layoutDependency: An array of values — layout animations only run when these values changelayoutScope: Groups elements that share layout animations togetherlayout="position": Only animate position, not sizelayout="size": Only animate size, not position
5. Exit Animations with AnimatePresence
AnimatePresence solves a fundamental React problem: when a component unmounts, it disappears instantly. AnimatePresence keeps elements in the tree long enough to animate them out.
Key Props
| Prop | Type | Description |
|---|---|---|
mode | "sync" | "wait" | "popLayout" | How entering/exiting components interact |
onExitComplete | () => void | Callback when all children have finished exiting |
custom | any | Custom data passed to variants for directional exits |
The mode Prop — Critical for UX
sync(default): New element enters while old exits — can cause overlapwait: Old exits completely, then new enters — no overlap but feels slowerpopLayout: Exiting elements collapse toposition: absoluteand animate out, while remaining siblings immediately re-layout — best for list mutations
Directional Exits with custom
Pass custom data to make exits animate in the logical direction:
1function PageTransition({ direction, children }) { 2 return ( 3 <AnimatePresence custom={direction} mode="wait"> 4 <motion.div 5 key={direction} 6 custom={direction} 7 variants={{ 8 enter: (dir) => ({ x: dir > 0 ? 300 : -300, opacity: 0 }), 9 center: { x: 0, opacity: 1 }, 10 exit: (dir) => ({ x: dir > 0 ? -300 : 300, opacity: 0 }), 11 }} 12 initial="enter" 13 animate="center" 14 exit="exit" 15 > 16 {children} 17 </motion.div> 18 </AnimatePresence> 19 ); 20}
6. The useAnimate Hook — Imperative Timeline Control
The useAnimate hook provides programmatic, timeline-like animation control. It returns a scope ref and a animate function, letting you define sequenced animations imperatively:
1import { useAnimate } from "framer-motion"; 2 3function AnimatedButton() { 4 const [scope, animate] = useAnimate(); 5 6 const handleClick = async () => { 7 await animate(scope.current, { scale: 0.95 }, { duration: 0.1 }); 8 await animate(scope.current, { scale: 1 }, { type: "spring" }); 9 await animate(".icon", { rotate: 360 }, { duration: 0.4 }); 10 }; 11 12 return ( 13 <motion.button ref={scope} onClick={handleClick}> 14 <span className="icon">🔄</span> Click Me 15 </motion.button> 16 ); 17}
The animate() function is awaitable — it returns a Promise that resolves when the animation completes. By chaining await calls, you create a sequential animation timeline without nested callbacks.
Animating Children
The animate function can target CSS selectors within the scope:
1// Animates all elements matching .particle inside scope 2await animate(".particle", { opacity: 0, y: -50 }, { delay: stagger(0.05) }); 3 4// You can also animate specific MotionValues 5await animate(x, 100, { type: "spring" });
Framer Motion API Comparison
When to use each advanced API based on use-case requirements
7. Gesture-Driven Animations
Framer Motion's gesture system ties directly into MotionValues for high-performance interactive animations.
Drag with Constraints and Physics
1<motion.div 2 drag 3 dragConstraints={{ left: -200, right: 200, top: -100, bottom: 100 }} 4 dragElastic={0.1} 5 dragTransition={{ bounceStiffness: 300, bounceDamping: 20 }} 6 whileDrag={{ scale: 1.05, boxShadow: "0 10px 30px rgba(0,0,0,0.3)" }} 7/>
| Prop | Type | Description |
|---|---|---|
drag | boolean | "x" | "y" | Enable drag on specific or all axes |
dragConstraints | RefObject | {top, right, bottom, left} | Bounding box or ref to container |
dragElastic | number | {top, right, bottom, left} | How far beyond constraints (0 = rigid, 1 = very elastic) |
dragMomentum | boolean | Whether element keeps sliding after release |
dragSnapToOrigin | boolean | Always spring back to initial position |
onDragStart/onDrag/onDragEnd | function | Lifecycle callbacks receiving drag info |
Gesture Shortcuts
1<motion.button 2 whileHover={{ scale: 1.05, backgroundColor: "#6366f1" }} 3 whileTap={{ scale: 0.95, backgroundColor: "#4f46e5" }} 4 whileFocus={{ outline: "2px solid #6366f1" }} 5 whileInView={{ opacity: 1, y: 0 }} 6 viewport={{ once: true, margin: "-100px" }} 7/>
The [whileInView](def="A gesture-trigger prop that animates an element when it enters the viewport, with optional one-time and margin settings") prop is particularly powerful for scroll-triggered animations and pairs with the viewport option to control intersection observer thresholds.
Advanced Framer Motion Learning Path
MotionValue Fundamentals
Phase 1Master useMotionValue, .get()/.set(), and binding to the style prop. Build a drag tracker that logs positions without re-renders."
Transformations & Scrolling
Phase 2Learn useTransform range mapping, useScroll with target/offset, and useSpring for smoothed scroll-linked animations."
Variant Orchestration
Phase 3Build staggered lists, dynamic variant functions with custom, and deeply nested propagated animations."
Layout & Shared Transitions
Phase 4Implement layout prop animations, layoutId for cross-component shared transitions, and FLIP-based multi-element morphing."
AnimatePresence & Exits
Phase 5Handle exit animations, directional exits with custom, mode prop options ('sync', 'wait', 'popLayout'), and list mutations."
Imperative Timelines
Phase 6Use useAnimate for awaitable animation sequences, CSS selector targeting, and complex choreographed timelines."
Advanced Topics & Edge Cases
Advanced Framer Motion Key Concepts
Knowledge Check
Which hook creates a reactive value that updates outside React's render cycle?
Explore Related Topics
Startup Fundamentals
The course outlines core concepts and stages to build, fund, and scale a startup.
- Define the problem, craft a value proposition, and validate with an MVP.
- Confirm product‑market fit using the “disappointed customer” rule and .
- Monitor burn rate, maintain a 12‑18 month runway, and control cash flow.
- Use a cap table to track equity, prevent over‑dilution, and prepare transparent pitch decks.
Retrieval-Augmented Generation (RAG) — From Fundamentals to Production-Ready Agentic RAG Systems
Retrieval‑Augmented Generation (RAG) couples external evidence retrieval with LLM generation to deliver up‑to‑date, grounded answers while mitigating hallucinations.
- Retrieval uses sparse (BM25), dense (vector embeddings) and hybrid methods; dense similarity is scored by cosine .
- Chunking strategy, metadata enrichment, and reranking are the highest‑leverage levers for retrieval quality and token efficiency.
- Production pipelines separate offline ingestion (parsing, chunking, embedding, indexing) from online serving (query rewriting, hybrid retrieval, reranking, context assembly, constrained generation).
- Agentic RAG extends standard RAG with planning, query decomposition, self‑critique, corrective retrieval loops, and tool use for multi‑hop or uncertain queries.
- Robust deployments require multi‑level evaluation (recall, precision, faithfulness, citations), observability of each stage, and governance of latency, cost, and access control.
React Hooks in Depth
This course explains React Hooks, the functional alternative to class components, covering core hooks, usage rules, performance optimizations, and how to create custom hooks.
useStateanduseEffectreplace class state and lifecycle methods; the dependency array controls when effects run.- Hooks must be called at the top level of React function components or custom hooks, and the ESLint plugin enforces these rules.
useMemomemoizes values anduseCallbackmemoizes functions, both improving performance for expensive calculations or stable callbacks.useReduceris preferred for complex state logic, following a reducer pattern similar to Redux.- Building a custom hook involves extracting reusable
useState/useEffectlogic into a function whose name starts with “use”.