Back to Blog
Master Framer Motion Animate Presence in React (2026 Guide) – cover image comparing React animation libraries

Master Framer Motion Animate Presence in React (2026 Guide)

·
Karan

Master Framer Motion Animate Presence in React (2026 Guide)

When it comes to building modern, fluid frontend applications in React, managing how components enter and leave the screen is a common challenge. React removes components from the DOM instantaneously, meaning developers are left scratching their heads figuring out how to trigger animations right before an element disappears. This is where Framer Motion Animate Presence becomes your ultimate superpower.

Whether you're developing a sleek dashboard for your SaaS company or injecting life into an indie hacker landing page, enabling effortless exit animations is essential in 2026. Without it, elements harshly blink out of existence. With it, your app feels polished, deliberate, and undeniably premium.

In this comprehensive guide, we'll dive deep into AnimatePresence. We will break down exactly how it works, explore real-world code examples, understand structural props like mode and custom, troubleshoot layout glitches, and ultimately show you how you can skip the tedious scratch-building entirely by leveraging a Framer Motion component library.

Key Takeaways

  • The Core Purpose: AnimatePresence intercepts React unmount operations and delays removal until a child’s exit animation completes.
  • The key Prop Requirement: Immediate children inside AnimatePresence must have a unique React key to be tracked accurately during re-renders.
  • Animation Modes: The mode prop (sync, wait, popLayout) dictates whether elements animate simultaneously or sequentially.
  • Deep Control Hooks: Advanced API hooks like `usePresence offer deep manual control down the React tree without prop drilling.

Table of Contents


What is Framer Motion Animate Presence?

At its core, React does not support lifecycle methods that pause a component's unmounting process. When state dictates that a component should no longer render, React strips it out of the DOM immediately.

For motion UI design, this is problematic. If you want a dropdown menu to smoothly fade out, you cannot simply attach CSS to a non-existent element. React unmounts it before the browser has time to calculate a transition frame.

Framer Motion Animate Presence acts as a guardian component. By wrapping dynamically rendered elements inside <AnimatePresence>, Framer Motion hooks into React's render phase. It detects when direct children are removed from the React tree, keeps them securely mounted in the DOM, fires the animation defined in their exit props, and then safely unmounts them. If you're building a Next.js app, managing these unmounts across page transitions is equally crucial—check out our guide on using Framer Motion with Next.js.

When does AnimatePresence track removals?

  1. An element mounting/unmounting conditionally (e.g., show && <Modal />).
  2. An element's key changing (effectively telling React this is a totally new element).
  3. Items being added or removed from a mapped array in a list.

Let's see how simple this is in practice with basic exit animations.


Getting Started: Basic Exit Animations

To begin using Framer Motion Animate Presence, make sure your project is set up with motion/react (or motion in recent versions).

import { motion, AnimatePresence } from "motion/react";
import { useState } from "react";
export default function ModalExample() {
const [showModal, setShowModal] = useState(false);
return (
<div>
<button onClick={() => setShowModal(!showModal)}>
Toggle Modal
</button>
{/* Wrapping the conditional render in AnimatePresence */}
<AnimatePresence>
{showModal && (
<motion.div
key="my-modal" // Critical: provide a unique key!
initial={{ opacity: 0, y: -20 }}
animate={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: 20 }} // Fires before unmounting
className="p-6 bg-white shadow-xl rounded-lg absolute"
>
<h2>Hello from the Modal!</h2>
<p>I animated in, and I will animate out smoothly.</p>
</motion.div>
)}
</AnimatePresence>
</div>
);
}

The Anatomy of the exit Prop

Notice the exit={{ opacity: 0, y: 20 }} property on the <motion.div>. Without AnimatePresence, the exit prop does absolutely nothing. But with the wrapper in place, setting showModal to false instructs AnimatePresence to hold the component hostage for a split second, execute the exit transition, and then clean up.


Controlling Elements with key Changes

The absolute most important rule when dealing with AnimatePresence is this: Direct children must each have a unique key prop.

Why? AnimatePresence compares the keys of its children on every render. If a key is missing or duplicated, it cannot definitively tell what entered and what exited.

Furthermore, simply changing a component's key triggers an enter/exit lifecycle immediately. This is the secret to building dynamic image galleries and Framer Motion carousels where only one item exists on-screen at a time, but elements need to cross-fade or slide past one another.

"use client";
import { motion, AnimatePresence, type Variants } from "motion/react";
import { useState } from "react";
import { ChevronLeft, ChevronRight } from "lucide-react";
const images = [
"https://images.unsplash.com/photo-1541701494587-cb58502866ab?q=80&w=800&auto=format&fit=crop",
"https://images.unsplash.com/photo-1550684848-fac1c5b4e853?q=80&w=800&auto=format&fit=crop",
"https://images.unsplash.com/photo-1507608616759-54f48f0af0ee?q=80&w=800&auto=format&fit=crop"
];
const variants: Variants = {
enter: (direction: number) => ({
x: direction > 0 ? 300 : -300,
opacity: 0
}),
center: {
zIndex: 1,
x: 0,
opacity: 1
},
exit: (direction: number) => ({
zIndex: 0,
x: direction < 0 ? 300 : -300,
opacity: 0
})
};
export default function AnimatePresenceSlideshowDemo() {
const [[page, direction], setPage] = useState<[number, number]>([0, 0]);
const paginate = (newDirection: number) => {
setPage([page + newDirection, newDirection]);
};
const index = Math.abs(page % images.length);
return (
<div className="flex flex-col items-center justify-center py-8 w-full ">
<div className="relative h-[250px] overflow-hidden w-full max-w-sm rounded-xl flex items-center justify-center flex-col">
<AnimatePresence initial={false} custom={direction}>
<motion.img
key={page}
src={images[index]}
custom={direction}
variants={variants}
initial="enter"
animate="center"
exit="exit"
transition={{
x: { type: "spring", stiffness: 300, damping: 30 },
opacity: { duration: 0.2 }
}}
className="w-full h-full object-cover absolute"
/>
</AnimatePresence>
<button
className="absolute left-2 top-1/2 -translate-y-1/2 z-10 w-8 h-8 flex items-center justify-center bg-black/50 hover:bg-black/70 rounded-full text-white"
onClick={() => paginate(-1)}
>
<ChevronLeft className="w-5 h-5" />
</button>
<button
className="absolute right-2 top-1/2 -translate-y-1/2 z-10 w-8 h-8 flex items-center justify-center bg-black/50 hover:bg-black/70 rounded-full text-white"
onClick={() => paginate(1)}
>
<ChevronRight className="w-5 h-5" />
</button>
</div>
</div>
);
}

Advanced Usage: The mode Prop

By default, AnimatePresence takes a somewhat chaotic approach: it animates exiting elements out and new elements in at the exact same time. Depending on your DOM layout, this might cause elements to jump or stack improperly.

You can modify this behavior using the mode prop. In 2026 frontend patterns, orchestrating this perfectly is non-negotiable for a premium feel.

1. mode="sync" (Default)

As described, entering and exiting children animate simultaneously. If you have two large divs, they will temporarily occupy the layout side-by-side unless you employ position: absolute.

2. mode="wait"

This is the most common modifier used by developers. The new entering element will literally wait until the exiting child has finished its exit animation before mounting and animating in. This guarantees sequential animations and prevents layout clashes, perfect for single-page application router transitions.

<AnimatePresence mode="wait">
<motion.div key={currentPage} exit={{ opacity: 0 }}>
<PageContent data={currentPage} />
</motion.div>
</AnimatePresence>

Pro Tip: For visually seamless wait transitions, try setting ease: "easeIn" on the exit animation, and ease: "easeOut" on the entering animation!

3. mode="popLayout"

When removing an item from a list, the exiting item normally takes up physical layout space until its exit animation completes. popLayout solves this. Exiting elements are figuratively "popped" out of the page layout (leveraging position: absolute under the hood), allowing all surrounding sibling elements to immediately reflow to fill the gap while the element fades out.

Note on popLayout: Ensure that the animating parent container has position: relative (or an offset parent), otherwise the absoluted child might fly off the page!

Component A
Static Sibling Element

Customizing AnimatePresence Behavior

Framer Motion equips us with additional props to finely tune how components behave within presence wrappers.

Disabling Initial Animations (initial={false})

Sometimes you mount a table or a feed of cards on the server or initial page load, and you don't want them doing a flashy entrance animation right away—you only want animations for items added after the initial mount.

<AnimatePresence initial={false}>
{items.map(item => <motion.li key={item.id} />)}
</AnimatePresence>

Passing Dynamic Values with The custom Prop

Exit animations evaluate when a component has already left the React tree. Because of this, it cannot receive updated props from its parent (like changes in scroll state or swipe direction).

To solve this, use the AnimatePresence custom prop. This prop streams the value down to exiting items securely via dynamic variants.

const slideVariants = {
hidden: (direction: number) => ({ x: direction > 0 ? 300 : -300, opacity: 0 }),
visible: { x: 0, opacity: 1 },
};
// ... inside render
<AnimatePresence custom={swipeDirection}>
<motion.div
key={activeSlide}
custom={swipeDirection}
variants={slideVariants}
initial="hidden"
animate="visible"
exit="hidden"
/>
</AnimatePresence>

Extending Control: The Presence Hooks

Framer Motion shines when you step beyond simple props and leverage the hook API.

usePresence()

For completely manual, custom animations (perhaps mixing Canvas, WebGL, or non-React libraries), usePresence() hands over control entirely. It gives you isPresent and a safeToRemove callback, ensuring React holds the node until you manually dispatch the removal alert.

import { usePresence } from "motion/react";
import { useEffect } from "react";
function CustomTimerComponent() {
const [isPresent, safeToRemove] = usePresence();
useEffect(() => {
if (!isPresent) {
// Delay unmount until my custom logic finishes
const timer = setTimeout(() => safeToRemove(), 1500);
return () => clearTimeout(timer);
}
}, [isPresent, safeToRemove]);
return <div className="spinner">Exiting manually</div>;
}

Troubleshooting Common Errors

1. "My Exit Animations aren't working whatsoever!"

  • The Culprit: You did not provide a key prop to the immediate child. Or worse, you used the array index as a key inside a .map().
  • The Fix: Provide a stable unique identifier to the direct child: key={item.uniqueId}.

2. "AnimatePresence doesn't work when I conditionally render the parent."

  • The Culprit: You are unmounting <AnimatePresence> itself!
  • The Fix: <AnimatePresence> must remain rendered in the DOM continuously to watch its children safely. Move the conditional inside the wrapper:
    • cond && <AnimatePresence><Component/></AnimatePresence>
    • <AnimatePresence>{cond && <Component/>}</AnimatePresence>

3. "My popLayout is displacing my elements wildly."

  • The Culprit: popLayout applies absolute positioning. If the parent element lacks position: relative, the exiting element will position relative to the root HTML body.
  • The Fix: Ensure the parent container has <motion.ul style={{ position: "relative" }}>.

Frequently Asked Questions (FAQ)

Q: Do I need AnimatePresence if I am only animating components on mount?
A: No! If you only want entrance animations using initial and animate, standard <motion.div> components work independently. You strictly need AnimatePresence if you wish to use the exit prop.

Q: Can I use CSS variables in exit animations?
A: Absolutely! Motion seamlessly interacts with CSS variables (e.g. exit={{ "--my-var": "#000" }}), making responsive design styling a breeze.


Supercharge Your React Animations with ogBlocks

Building basic transitions with Framer Motion Animate Presence is an essential front-end skill. You now have the knowledge to build carousels, animate modals, and control layout reflows flawlessly. However, as an indie hacker, developer, or SaaS founder building products in 2026, time is your most precious asset.

When you want to craft complex hero headers, mesmerizing spinning texts, scrolling marquees, or intricate staggered letter reveal animations, coding them from scratch via motion variants can absorb hours of your sprint cycle. Animations should accelerate your launch, not delay it.

This is precisely why we created ogBlocks.

ogBlocks is a premium component library brimming with spectacular text animations and highly polished UI components built expressly on top of React and Framer Motion. (If you're still deciding on animation libraries, you can read our comparison of Framer Motion vs React Spring to see why we chose Motion). Don't waste time wrangling usePresence and complicated math to get an elite aesthetic layout. Simply browse our component library, copy the beautifully optimized code blocks, and instantly elevate your React app's visual identity.

Stop debugging layout shifts and math. Get ogBlocks and make your app truly unforgettable.

Written by Karan

ogBlocks is an Animated React UI Component library built with Motion and Tailwind CSS

Master Framer Motion Animate Presence in React (2026 Guide) | OGBlocks Blog | ogBlocks