Smooth Shared Layout Transitions in Framer Motion with layoutId and animatePresence
Learn how Framer Motion’s layoutId and animatePresence create smooth shared layout transitions when reordering a list, with a worked example and verification steps.
01 Jun 2026, 04:42 UTC

The problem: jumping items when you reorder a list
When you let users drag‑and‑drop to reorder a list of cards, the default React render causes the moving card to disappear from its old spot and appear instantly at the new index. The visual jump breaks the feeling of continuity and can be disorienting, especially if the cards contain varied sizes or images.
How layoutId and animatePresence enable a shared layout transition
Framer Motion’s layoutId prop tells the library to treat two elements as the same visual entity even if they live in different places in the DOM. When those elements are wrapped by <animatePresence>, the library measures the layout of the exiting and entering elements and animates the change in position and size instead of a sudden swap. The key requirements are:
- Each motion component that should participate gets a stable
layoutId(commonly the item’s unique key). - The components are direct children of
<animatePresence>– extra wrappers or conditional unmounting break the measurement. - The list is rendered in the order of the underlying data array; when that order changes, Framer Motion calculates the transition automatically.
Worked example: a reorderable card list
Below is a minimal React component that demonstrates the technique. Copy it into a project with framer-motion@^4.0 installed (npm i framer-motion) and run it to see the effect.
import { useState } from 'react';
import { motion, AnimatePresence } from 'framer-motion';
const cards = [
{ id: 1, title: 'First', color: '#ff9999' },
{ id: 2, title: 'Second', color: '#99ff99' },
{ id: 3, title: 'Third', color: '#9999ff' },
];
export default function ReorderableList() {
const [order, setOrder] = useState(cards);
const handleDragEnd = (result) => {
if (!result.destination) return;
const reordered = Array.from(order);
const [moved] = reordered.splice(result.source.index, 1);
reordered.splice(result.destination.index, 0, moved);
setOrder(reordered);
};
return (
Drag to reorder
{order.map((card, index) => (
{card.title}
Position {index + 1}
))}
);
}
When you drag a card, the layoutId stays attached to the same DOM node throughout the drag. <animatePresence> keeps the outgoing card in the DOM until its fade‑out completes, allowing Framer Motion to animate the node from its old coordinates to the new ones.
Trade‑offs, limitations and how to verify the result
Performance: Each layoutId triggers a layout measurement. For very long lists (hundreds of items) this can impact frame‑rate. A practical mitigation is to virtualize the list or limit the number of simultaneously animated items (e.g., animate only the dragged card and its immediate neighbours).
Nesting rules: The animated element must be a direct child of <animatePresence>. Adding an extra wrapper like a <div> for styling will break the shared transition because the library can no longer match the layout nodes.
To confirm that layoutId is responsible for the smooth glide:
- Run the example and drag a card – notice the fluid movement.
- Open React DevTools, select a motion card, and verify that its
layoutIdprop equals the card’sidand does not change during the drag. - Temporarily remove the
layoutIdline (or set it to a static value likelayoutId="fixed") and repeat the drag. The card will now jump to its new index, confirming that the shared layout transition depends on the matching IDs.
Actionable closing
If you need a reorderable list that feels native, start by wrapping your items in <animatePresence>, give each a stable layoutId based on your data key, and render the list in the order of your state array. Test the animation with the verification steps above, and watch for performance cues if your list grows large. With these steps you’ll get a smooth shared layout transition without writing custom animation logic.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.