# Framer Motion Recipes Import from `motion/react` (v11+). All examples are React + Framer Motion. ```jsx import { motion, AnimatePresence, Reorder, useReducedMotion, useDragControls } from "motion/react"; ``` ## Variants and staggered children Variants are named animation states a parent can propagate to children, enabling orchestration like staggering without per-child timing math. ```jsx const list = { hidden: { opacity: 0 }, show: { opacity: 1, transition: { staggerChildren: 0.06, delayChildren: 0.1 }, }, }; const item = { hidden: { opacity: 0, y: 12 }, show: { opacity: 1, y: 0, transition: { type: "spring", stiffness: 500, damping: 30 } }, }; {items.map((t) => ( {t.label} ))} ``` `staggerDirection: -1` staggers from last to first. `when: "beforeChildren"` / `"afterChildren"` sequences parent vs children. ## AnimatePresence modes ```jsx {/* outgoing finishes before incoming starts (route/tab switches) */} ``` Modes: - default (`"sync"`) — incoming and outgoing animate simultaneously. - `"wait"` — finish exit before enter (single-element swaps like tabs/pages). - `"popLayout"` — exiting items are popped from layout flow so siblings re-flow immediately (toast stacks, removing list items). Children must be capable of `layout`. Require a unique, stable `key` on each child. To run exit on initial mount too, that is not needed; to suppress enter animation on first render set ``. ## Toast stack (popLayout + layout) ```jsx function Toasts({ toasts }) { return (
{toasts.map((t) => ( {t.message} ))}
); } ``` `layout` makes remaining toasts slide up smoothly when one is dismissed. ## Magic-move / shared-element layout ```jsx function Gallery() { const [active, setActive] = useState(null); return ( <>
{photos.map((p) => ( setActive(p)} /> ))}
{active && ( setActive(null)} initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }}> )} ); } ``` Matching `layoutId` makes the thumbnail visually fly to the lightbox and back. ## Drag-to-reorder list `Reorder` handles pointer drag, axis locking, and live reordering with layout animation built in. ```jsx function SortableList({ items, setItems }) { return ( {items.map((item) => ( {item} ))} ); } ``` For a dedicated drag handle, use `useDragControls`: ```jsx const controls = useDragControls(); controls.start(e)}>⠿ {item.label} ``` ## Drag with constraints and elastic ```jsx const ref = useRef(null);
``` `dragElastic` (0–1) controls how far past constraints it can be pulled; `dragSnapToOrigin` returns it on release. ## Gesture composition (like button) ```jsx function Like() { const [liked, setLiked] = useState(false); return ( setLiked((v) => !v)} whileTap={{ scale: 0.85 }}> ♥ ); } ``` Arrays of values (`scale: [1, 1.4, 1]`) are keyframes; control their spacing with `times: [0, 0.6, 1]`. ## Respecting reduced motion ```jsx function Panel() { const reduce = useReducedMotion(); return ( ); } ``` Wrap an app in `` to globally strip transform/layout animations for users who prefer reduced motion while keeping opacity. ## Performance notes - Prefer `transform`/`opacity`; Framer Motion already uses transforms for `x/y/scale/rotate`. - For frequently-updated values (cursor follow, scroll), use `useMotionValue` + `useSpring` instead of React state to avoid re-renders. - `layout` is powerful but measure-heavy; avoid putting it on hundreds of simultaneously-animating nodes. --- Tune the timing and easing and a micro-interaction feels effortless. Built by **[iart.ai](https://iart.ai/?utm_source=github&utm_medium=readme&utm_campaign=web-animation-skills&utm_content=skill_footer&utm_term=micro-interaction)** — the AI motion agent for editable, on-brand motion graphics.