EmpireUI
Get Pro
← Blog8 min read#auto-animate#react#layout animation

AutoAnimate in React: Zero-Config Layout Animations in 3 Lines

AutoAnimate adds smooth layout animations to any React list or conditional in 3 lines - no keyframes, no Framer Motion setup, no props. Here's exactly how it works.

Colorful animated UI elements transitioning smoothly on a dark screen

What AutoAnimate Actually Is

AutoAnimate is a zero-config animation utility from the FormKit team that shipped in 2022 and hasn't really needed to change since - the core API is that settled. You give it a parent DOM element, it watches for children being added, removed, or moved, and then plays smooth CSS transitions automatically. That's it. No prop drilling, no wrapping components in motion tags, no fighting with spring configs.

The install is one package: @formkit/auto-animate. The React integration ships a hook - useAutoAnimate - that returns a ref you attach to any container. Everything inside that container gets animated from that point on. You're looking at maybe 2.5 kB gzipped. Framer Motion is closer to 40 kB. That's not a knock on Framer Motion, which is genuinely great for complex animation orchestration, but if you're just animating a todo list or a filtered grid, AutoAnimate is the right tool.

Honestly, it's the library you reach for when your designer says "can you make that feel a bit smoother?" and you have 10 minutes. Compared to hand-rolling CSS scroll animations or wiring up keyframes for every state transition, AutoAnimate is in a different league for the effort-to-result ratio.

The 3-Line Setup

Install first. One command, no peer dependency drama:

npm install @formkit/auto-animate

Then in your component:

import { useAutoAnimate } from '@formkit/auto-animate/react'

export function TodoList({ items }: { items: string[] }) {
  const [parent] = useAutoAnimate()

  return (
    <ul ref={parent}>
      {items.map((item) => (
        <li key={item}>{item}</li>
      ))}
    </ul>
  )
}

That's the whole thing. Add an item to items, it fades and slides in. Remove one, it slides out. Reorder the array, each item moves to its new position with a smooth translate. Worth noting: you don't animate the children - you animate the *parent*. That's the mental model shift, and once it clicks everything becomes obvious.

The useAutoAnimate hook returns a tuple. Index 0 is the ref, index 1 is a function to enable/disable animation at runtime - handy if you want to skip animation during bulk operations or while an initial data load is happening. Quick aside: if you're not using React, the library also exports a vanilla autoAnimate(element) function that works identically on any DOM node.

Configuring the Animation (Without Writing Keyframes)

By default you get a 250ms ease-in-out animation - which actually looks decent out of the box. But you can override the easing and duration through the options object passed to useAutoAnimate:

const [parent] = useAutoAnimate({
  duration: 350,
  easing: 'ease-out',
})

If you want something springier, you can pass a custom keyframes function. The function receives the element and a data object with old and new DOMRects, which lets you compute pixel-perfect transforms yourself. In practice, most teams never touch this - the default is already solid for list UIs.

One more thing - disrespectUserMotionPreference is an option that defaults to false, meaning AutoAnimate automatically respects prefers-reduced-motion and skips animations for users who've set that preference. This is what correct behavior looks like by default, which is more than you can say for a lot of animation libraries.

For matching your component's visual style, you'd pair AutoAnimate with the container styles from your design system. If you're building something with a glassmorphism aesthetic, check out the glassmorphism generator to pull the right backdrop-filter values - an animated frosted card list looks genuinely great.

Conditional Rendering and Mount/Unmount Animations

This is where AutoAnimate surprises people. You don't need a list to use it. Wrapping conditional content in a parent with AutoAnimate applied means mount/unmount gets animated too:

import { useAutoAnimate } from '@formkit/auto-animate/react'

export function Drawer({ isOpen }: { isOpen: boolean }) {
  const [parent] = useAutoAnimate()

  return (
    <div ref={parent}>
      {isOpen && (
        <div className="drawer-content">
          <p>Hidden until opened</p>
        </div>
      )}
    </div>
  )
}

The wrapper div stays in the DOM. The inner drawer-content div animates in when isOpen flips to true and animates out when it flips back. The exit animation is the part that's traditionally painful to get right in React - you normally need something like AnimatePresence from Framer Motion, or you manually coordinate a CSS class before removing the element. AutoAnimate just... handles it.

That said, there's a real limitation here: AutoAnimate doesn't give you direct control over enter vs exit animations independently. Every transition uses the same easing and duration. If your design requires a fast snap-in and a slow ease-out, you'll need to write a custom keyframes function or reach for Framer Motion instead. For 80% of UI animations, AutoAnimate is all you need. For the other 20%, you'll know pretty quickly.

Where AutoAnimate Falls Short

Look, no library is magic. AutoAnimate works by reading getBoundingClientRect() before and after DOM changes, then playing a FLIP animation (First, Last, Invert, Play - a technique Google proposed around 2015). This is great for simple layout shifts, but it can produce unexpected results if you're animating elements that change their own size mid-animation, or if you're nesting multiple AutoAnimate parents deep in the tree.

Nested AutoAnimate parents can fight each other. If you put a useAutoAnimate ref on both a list and the list's container, you'll sometimes see items double-animating or jittering. The fix is simple: only apply it to the most specific parent that contains the changing children.

Performance is another consideration. FLIP animations are GPU-friendly because they rely on transform rather than top/left/width changes. But if you've got 500+ items animating simultaneously, even GPU compositing hits limits. In those cases you'd want virtualization (react-window, tanstack-virtual) and skip AutoAnimate for the list itself - maybe just animate the count badge or the filter controls.

For anything beyond layout transitions - dragging, physics springs, scroll-linked animations, stagger effects - you want Framer Motion or something purpose-built. AutoAnimate doesn't try to compete there. It's a sharp tool for a specific job. Speaking of stagger and motion polish, if you're building a styled UI with animations that need to feel intentional, browse components at Empire UI - a lot of the motion-heavy component variants already have this stuff wired in.

AutoAnimate vs Framer Motion: When to Pick Which

The honest comparison: Framer Motion is a full animation engine. AutoAnimate is a helper. They're not really competing - you might use both in the same app for different things.

Use AutoAnimate when you have a list that adds, removes, or reorders items; when you want conditional mount/unmount transitions without ceremony; when bundle size is a concern; or when you just want something to feel alive with minimal code. The 2.5 kB footprint means it's free for nearly any project.

Use Framer Motion when you need gesture-driven animation, scroll-linked progress, stagger orchestration across multiple elements, or custom exit animations that differ from enter animations. Framer Motion in 2026 is version 11+ and the API is excellent - but it does require you to think about animation as a first-class concern in your component tree. That's the right trade-off for complex UI, but overkill for a filtered search result list.

In practice, my default is to start with AutoAnimate and only pull in Framer Motion when I hit something AutoAnimate can't do. The upgrade path is clean - you can keep AutoAnimate on some parents and swap specific components to Framer Motion without conflicts.

FAQ

Does AutoAnimate work with React 18 concurrent features?

Yes. The useAutoAnimate hook is compatible with React 18+ including Strict Mode and concurrent rendering. You might see double-mount warnings in dev mode, but production behavior is correct.

Can I use AutoAnimate with Tailwind CSS classes?

Absolutely - AutoAnimate doesn't care about how you style elements. Just attach the ref to the parent container and add Tailwind classes however you normally would.

Why isn't my exit animation playing?

The most common cause is that the parent element isn't staying mounted. The ref needs to be on a stable wrapper element that persists in the DOM - AutoAnimate watches its children, so the parent itself can't be the thing that unmounts.

How do I disable AutoAnimate animation during initial page load?

Use the second return value from useAutoAnimate: const [parent, enable] = useAutoAnimate(). Call enable(false) before your data loads and enable(true) after. This skips the animation for the first render.

Free components in 40 styles
React & Tailwind, copy-paste ready.
Browse →

Read next

Framer Motion Advanced: Layout Animations, Shared Elements, useAnimateFramer Motion Layout Animations: shared layout, AnimatePresenceHTML Canvas Animations in React: Particles, Noise Fields, MoreLottie Animations in React: Setup, Optimisation and Pitfalls