Animations cheatsheet. Library used: Motion (formerly Framer Motion).

Install

npm i motion
import { motion } from "motion/react";

Basic

<motion.div
  initial={{ opacity: 0, y: 20 }}
  animate={{ opacity: 1, y: 0 }}
  transition={{ duration: 0.3 }}
>
  Hello
</motion.div>

Hover / tap

<motion.button
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
>
  Click
</motion.button>

Variants

const variants = {
  hidden: { opacity: 0, y: 20 },
  visible: { opacity: 1, y: 0 },
};

<motion.div initial="hidden" animate="visible" variants={variants} />

Variants are reusable + can be propagated to children:

const container = {
  visible: { transition: { staggerChildren: 0.1 } },
};

<motion.ul initial="hidden" animate="visible" variants={container}>
  {items.map((it) => (
    <motion.li key={it.id} variants={item}>{it.name}</motion.li>
  ))}
</motion.ul>

AnimatePresence (exit anim)

import { AnimatePresence } from "motion/react";

<AnimatePresence>
  {open && (
    <motion.div
      key="dialog"
      initial={{ opacity: 0 }}
      animate={{ opacity: 1 }}
      exit={{ opacity: 0 }}
    />
  )}
</AnimatePresence>

AnimatePresence watches direct children — they need stable keys. Without it, exit animations don’t run.

Layout animations

<motion.div layout>
  ...
</motion.div>

When the layout changes (size/position), motion animates to the new position. Magic for flexbox/grid reordering.

{items.map((it) => (
  <motion.div key={it.id} layout>
    {it.name}
  </motion.div>
))}

LayoutId (shared element transitions)

{!expanded && <motion.div layoutId="card" />}
{expanded && <motion.div layoutId="card" className="fullscreen" />}

Motion animates between the two states across mount/unmount.

Spring transitions

<motion.div transition={{ type: "spring", stiffness: 200, damping: 20 }} />

Spring physics. Tune stiffness (higher = faster) and damping (higher = less bounce).

Stagger

const container = {
  visible: {
    transition: { staggerChildren: 0.05, delayChildren: 0.2 },
  },
};

drag

<motion.div
  drag
  dragConstraints={{ left: 0, right: 300, top: 0, bottom: 200 }}
  dragElastic={0.2}
/>

Track drag position:

<motion.div
  drag="x"
  onDragEnd={(e, info) => console.log(info.offset.x, info.velocity.x)}
/>

useMotionValue / useTransform

const x = useMotionValue(0);
const opacity = useTransform(x, [-100, 0, 100], [0, 1, 0]);

<motion.div style={{ x, opacity }} drag="x" />

Lower-level: subscribe to motion values without re-rendering.

Scroll-linked

import { useScroll, useTransform } from "motion/react";

const { scrollYProgress } = useScroll();
const opacity = useTransform(scrollYProgress, [0, 1], [1, 0]);

<motion.div style={{ opacity }} />

Whilst in view

<motion.div
  initial={{ opacity: 0, y: 50 }}
  whileInView={{ opacity: 1, y: 0 }}
  viewport={{ once: true, margin: "0px 0px -100px 0px" }}
/>

Triggers when scrolled into view.

Animate gesture

<motion.button
  animate={{ rotate: clicked ? 360 : 0 }}
  transition={{ duration: 0.5 }}
  onClick={() => setClicked(!clicked)}
/>

Reduce motion

import { useReducedMotion } from "motion/react";

const reduce = useReducedMotion();

<motion.div animate={reduce ? {} : { x: 100 }} />

Respect prefers-reduced-motion.

CSS transitions (sometimes better)

.card { transition: transform 200ms ease; }
.card:hover { transform: translateY(-4px); }

For simple state-driven animations, CSS is lighter than Motion.

View Transitions API (browser)

function nav(to: string) {
  if (!document.startViewTransition) { setRoute(to); return; }
  document.startViewTransition(() => { setRoute(to); });
}

Native cross-fades, no JS animation engine. Great for route transitions.

Common mistakes

  • AnimatePresence with non-direct children — exit doesn’t run.
  • Missing key on AnimatePresence children — same element, no exit.
  • Animating width: auto — won’t animate. Animate width: 100% from 0.
  • Heavy animations on layout-thrashing props — use transform/opacity.
  • Forgetting useReducedMotion — accessibility issue.

Read this next

If you want my animation snippets + reduced-motion utils, they’re at rajpoot.dev .


Building something AI-, backend-, or data-heavy and want a second pair of eyes? I do consulting and freelance work — see my projects and ways to reach me at rajpoot.dev .