List Transitions
Published Jun 9, 2026
⋅
Updated Jun 12, 2026
⋅
1 minutes read
Animating a list is where exit animations earn their keep. Add and remove items below — each one enters and leaves on the same spring, and the rest of the list slides to fill the gap instead of snapping.
- Item 1
- Item 2
- Item 3
The pieces
A few rules from the wiki make this work:
exit-requires-wrapper— conditionally rendered motion elements need anAnimatePresencewrapper, or the exit animation never runs.exit-key-required— keys must be stable identities, not array indices. Index keys make React reuse the wrong element and the animation lands on the wrong row.exit-matches-initial— the exit state mirrorsinitialfor symmetry; what fades in the same way fades out.mode-pop-layout-for-lists—mode="popLayout"pulls exiting items out of layout flow so the survivors can animate into place cleanly.
<AnimatePresence mode="popLayout" initial={false}>
{items.map((item) => (
<motion.li
key={item.id}
layout
initial={{ opacity: 0, y: 8, scale: 0.98 }}
animate={{ opacity: 1, y: 0, scale: 1 }}
exit={{ opacity: 0, y: 8, scale: 0.98 }}
transition={{ type: "spring", stiffness: 500, damping: 30 }}
/>
))}
</AnimatePresence>Don't click a ghost
While an item plays its exit animation it's still mounted. presence-disable-interactions says to disable pointer events on exiting elements so you can't click something that's halfway gone. The demo reads useIsPresent() inside each row and sets pointerEvents: "none" once it starts leaving.