# Framer Motion: The Animation Library That Thinks in React
By Govind Bajaj · 2025

Tags: framer-motion, react, animation, ui, frontend
I replaced 400 lines of CSS animation with 40 lines of Framer Motion. The animations got better. The code got maintainable. Here's when to use it — and when not to.
I replaced four hundred lines of CSS keyframes and transition classes with forty lines of Framer Motion last month.

The animations got smoother. The entrance effects became orchestrated instead of chaotic. And the code became maintainable — each animation is now a declarative prop instead of a separate CSS file that nobody wanted to touch.

But Framer Motion is not always the right tool. Used incorrectly, it adds 30KB to your bundle for a fade effect CSS could do in five lines. Here is how I decide when to use it and when to skip it.

## When Framer Motion Is Worth It

Framer Motion shines for orchestrated animations. AnimatePresence for mount and unmount transitions, layout animations for automatic position changes, drag interactions with gesture support, staggered children animations, and shared layout animations between routes.

If your animation involves multiple elements moving in coordination, Framer Motion saves significant complexity. If it is a single hover effect, use CSS.

## The AnimatePresence Pattern

The most common use case: smoothly removing elements from the DOM. React removes elements immediately. AnimatePresence delays the unmount until the exit animation completes.

```tsx
import { AnimatePresence, motion } from "framer-motion"

function OrderList({ orders }: { orders: Order[] }) {
  return (
    <ul>
      <AnimatePresence mode="popLayout">
        {orders.map(order => (
          <motion.li
            key={order.id}
            layout
            initial={{ opacity: 0, y: 20 }}
            animate={{ opacity: 1, y: 0 }}
            exit={{ opacity: 0, x: -100 }}
            transition={{ duration: 0.2 }}
          >
            {order.name}
          </motion.li>
        ))}
      </AnimatePresence>
    </ul>
  )
}
```

The key prop is required — it lets Framer Motion track which element is entering, leaving, or staying. The layout prop automatically animates position changes when items reorder. The initial, animate, and exit props define the three animation states.

## Layout Animations Without Measuring

CSS cannot animate layout changes smoothly. If a sidebar expands and content reflows, CSS jumps instantly. Framer Motion measures the before and after positions and animates between them automatically.

```tsx
<motion.div layout style={{ width: isOpen ? 300 : 80 }}>
  {/* Content automatically animates to new position */}
</motion.div>
```

The layout prop tells Framer Motion to track this element's position. When it changes, Framer Motion animates the transition. No manual measurements. No complex calculation code.

## Gesture-Based Interactions

```tsx
<motion.div
  drag
  dragConstraints={{ left: 0, right: 0, top: 0, bottom: 0 }}
  dragElastic={0.2}
  whileHover={{ scale: 1.05 }}
  whileTap={{ scale: 0.95 }}
/>
```

Drag with constraints, elastic snap-back, hover scaling, and tap feedback — all declarative, all in six lines. Implementing this in CSS or raw JavaScript would require significantly more code and would not be as smooth.

## When to Skip Framer Motion

Do not use Framer Motion for simple hover effects that CSS handles better:

```css
/* Use CSS for this */
.button:hover { transform: scale(1.05); }
.button { transition: transform 0.2s; }
```

Do not use it for scroll-triggered animations where IntersectionObserver and CSS suffice. Do not use it if bundle size is critical — Framer Motion adds approximately 30KB gzipped. And do not use it for canvas or WebGL animations — it is a DOM animation library.

## Performance Considerations

Framer Motion uses the Web Animations API and hardware-accelerated transforms (translate, scale, rotate). These are GPU-composited and run at 60fps.

Avoid animating layout properties (width, height, top, left) that trigger browser layout recalculation. Use scale and translate transforms instead.

## Takeaways

- Framer Motion is for orchestrated, multi-element animations — not single hover effects
- AnimatePresence handles mount and unmount animations that React cannot do natively
- The layout prop animates position changes automatically without manual measurement
- Gesture support (drag, hover, tap) is declarative and smooth
- CSS transitions are still better for simple hover effects and color changes
- The 30KB bundle is worth it for complex UIs, skip it for static pages
- Always use transform properties (translate, scale, rotate) for 60fps animations
- 400 lines of CSS keyframes became 40 lines of declarative animation props