Animating Dismissible Components with Framer Motion's AnimatePresence
Animate components before they unmount with Framer Motion's AnimatePresence. Learn how to implement exit animations for dismissible UI elements like alerts and list items.
05 Aug 2025, 07:31 UTC

The Problem: Jarring Disappearances in React UIs
When a component disappears from the screen—like a toast notification, modal, or list item—the transition can feel abrupt and jarring. CSS alone can't animate out of existence because the element is removed from the DOM. This creates a poor user experience where users lose visual continuity.
Thesis: Framer Motion's AnimatePresence component solves this by keeping a component in the DOM during its exit animation, then cleanly removing it afterward.
How AnimatePresence Works
AnimatePresence wraps your conditional rendering. When a child is about to unmount, AnimatePresence pauses the unmount, applies the exit animation, then removes the element. This works with any motion.* component that has an exit prop defined.
Key Props and Patterns
exitBeforeEnter- Waits for exit animation to finish before starting the next enter animation. Prevents layout jumps.initial={false}- Skips the initial animation on mount. Useful when you want to animate only exit.exit- Defined on the motion component, specifies the exit animation variant or object.
Worked Example: Dismissible Alert Component
Here's a practical implementation for a dismissible alert:
import { AnimatePresence, motion } from 'framer-motion';
import { useState } from 'react';
export function Alert({ message }) {
const [visible, setVisible] = useState(true);
const alertVariants = {
hidden: { opacity: 0, y: -20 },
visible: { opacity: 1, y: 0 },
exit: { opacity: 0, y: -20 }
};
return (
<AnimatePresence initial={false}>
{visible && (
<motion.div
variants={alertVariants}
initial="hidden"
animate="visible"
exit="exit"
transition={{ duration: 0.3 }}
className="alert"
>
<p>{message}</p>
<button onClick={() => setVisible(false)}>
×
</button>
</motion.div>
)}
</AnimatePresence>
);
}
Layout Animations and Structural Changes
When combined with layout prop, AnimatePresence can handle complex exit scenarios. For example, removing an item from a list with smooth reflow:
import { AnimatePresence, motion } from 'framer-motion';
export function TodoList({ items, onDelete }) {
return (
<AnimatePresence exitBeforeEnter>
{items.map(item => (
<motion.div
key={item.id}
layout
initial={{ opacity: 1, y: 0 }}
exit={{ opacity: 0, y: -10 }}
transition={{ duration: 0.2 }}
className="todo-item"
>
{item.text}
<button onClick={() => onDelete(item.id)}>
Delete
</button>
</motion.div>
)}
</AnimatePresence>
);
}
Trade-offs and Limitations
Server-side rendering: AnimatePresence tracks presence client-side. Wrap it in a check like if (typeof window === 'undefined') or use lazy loading to avoid hydration mismatches.
Performance: Complex exit animations with many elements can impact lower-end devices. Keep exit animations simple—opacity and transform changes are cheapest.
Exit prop requirement: Every component you want to animate out must have an exit prop. Forgetting this results in instant disappearance.
Verification Steps
- Install Framer Motion:
npm install framer-motion - Create a component with conditional rendering wrapped in
AnimatePresence - Add
exitprop to your motion component - Toggle visibility and observe the exit animation
- Check Framer Motion v11 documentation for any API updates
Actionable Takeaways
- Use
AnimatePresencefor any component that conditionally renders and needs an exit animation - Always define an
exitprop on motion components you want to animate out - Consider
exitBeforeEnterfor lists where multiple items might animate sequentially - Test on target devices—complex exit animations can degrade performance
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.