Cheatsheet

Cheatsheet — Motion

Which API for which job

NeedUseNot
Declarative animation tied to component stateanimate prop / variantsimperative animate() for simple cases
One-off imperative sequence (timeline-like)useAnimatechaining many animate prop changes
Value that updates every frame without re-renderuseMotionValue / useTransformuseState + re-render
Animate on scroll positionuseScroll (+ useTransform)manual scroll listeners
Physics-feel motion (drag release, follow-cursor)useSpring / spring transitiontween with a guessed duration
Predictable, fixed-length animationtween transitionspring (spring duration isn't fixed)
Exit-before-unmount animationAnimatePresence + exitconditional render without wrapper
Position/size change on layout shiftlayout propmanually animating top/left/width
Shared-element transition across componentslayoutIdseparate independent layout animations
Sequenced children animationstaggerChildren on parent variantper-child manual delay values

Transition type decision rule

  • Use spring when the motion should feel physical/interactive (drag, gesture-driven, follow-cursor). Default choice for whileHover/whileTap/whileDrag.
  • Use tween when duration must be exact and predictable (progress bars, timed reveals, anything synced to another fixed-duration event).
  • Default to spring for anything gesture-adjacent, because it "arrives" more naturally, only switch to tween when a fixed duration is a hard requirement.

Performance rules of thumb

  • Animate transform and opacity first; treat any other animated property as a potential jank source.
  • Scope the layout prop to the smallest subtree that actually changes, not a whole page wrapper.
  • Don't assume requestAnimationFrame runs every ~16ms in every browser/tab state, Safari/Firefox can throttle it.

Accessibility defaults

  • Set reducedMotion once via MotionConfig at the app root instead of per-component checks.
  • "user" respects the OS setting; "always" forces reduced motion regardless of OS setting, use sparingly.

Common error → likely cause (see Troubleshooting chapter for the full table)

  • "Trying to perform an animation on null" → selector found nothing, or a ref hasn't hydrated yet.
  • "Cubic bezier arrays must contain four numerical values" → an ease array has the wrong length.
  • Drag constraint errors → the dragConstraints ref points at an element that isn't mounted/hydrated yet.

Framework note

React and Vue APIs mirror each other closely (useSpring/useSpring, motion.div/motion.div, etc.); when in doubt, the React doc chapter's concepts transfer directly, only the component syntax differs. Vanilla JS uses the lower-level animate(), scroll(), and motion-value functions directly, without hooks.