Using Framer Motion’s layout animation for smooth list reorders
Learn how Framer Motion’s layout prop animates list reorders with zero CSS, plus practical limits and verification steps.
17 Dec 2025, 19:27 UTC

The problem: jarring list changes
When a React list reorders, items jump to their new positions instantly. Users perceive this as a sudden shift, which can feel disorienting, especially on touch‑enabled interfaces where a fluid motion reinforces the sense of direct manipulation.
Thesis: enable layout animation with minimal code
Framer Motion’s layout prop automatically animates position and size changes using the FLIP technique. By adding a single prop (or a stable layoutId for shared animations) you get 60 fps, GPU‑accelerated transitions without writing CSS keyframes or managing timers.
How it works
When a component wrapped in <motion.div layout> changes its layout (e.g., its top, left, width or height), Framer Motion captures the element’s initial paint, measures the final layout, and interpolates transform and opacity between the two states. The browser’s compositor handles the interpolation, keeping the main thread free for other work.
For shared layout animations—like when an item moves from a list to a detail panel—you assign the same layoutId to both elements. Framer Motion matches the IDs across renders and animates the element as if it “moved” between the two positions.
Worked example: reordering a todo list
import { motion, AnimatePresence } from 'framer-motion';
import { useState } from 'react';
function TodoList() {
const [items, setItems] = useState([
{ id: 'a', text: 'Buy milk' },
{ id: 'b', text: 'Walk dog' },
{ id: 'c', text: 'Write report' },
]);
const handleDragEnd = (result) => {
if (!result.destination) return;
const reordered = Array.from(items);
const [moved] = reordered.splice(result.source.index, 1);
reordered.splice(result.destination.index, 0, moved);
setItems(reordered);
};
return (
{items.map((item, index) => (
{item.text}
))}
);
}
export default TodoList;
The layout prop on each motion.div triggers the animation when the drag‑end handler reorders the items array. No additional CSS or animation definitions are required.
Trade‑off and limitation
Animating many items simultaneously can exceed the browser’s frame budget. If you animate a long list (e.g., >30 items) you may see dropped frames. A practical mitigation is to limit layout‑animated items to the visible window—using a virtualization library like react-window—or to animate only the items that actually change position.
Another limitation concerns layoutId: the ID must be stable and unique across renders. Changing the ID between renders aborts the shared animation and causes an instant jump, which can be confusing if IDs are derived from volatile data.
Actionable closing
To verify that layout animation is active:
- Run the example in a local React app with Framer Motion v10+ installed.
- Open Chrome DevTools → Performance, record a drag‑to‑reorder action.
- Check that the Layout and Paint sections stay under ~16 ms per frame.
- Remove the
layoutprop (or change thelayoutId) and repeat the recording; you should see the layout jump instantly and the layout time drop to near zero.
If the performance stays within budget and the motion feels smooth, you’ve successfully leveraged Framer Motion’s layout animation. For larger datasets, combine this technique with windowing to keep the animated item count low and maintain 60 fps.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.