Using Framer Motion Layout Animations for Smooth DOM Reordering
Learn how Framer Motion's layout prop and layoutId create smooth DOM reordering and shared element transitions using the FLIP technique.
13 Aug 2026, 02:47 UTC

The Problem: UI Jumps When the DOM Changes
When a React component re‑orders a list, filters a grid, or swaps a card for a detail view, the browser updates the DOM instantly. To the user this appears as a sudden “jump” where elements snap to their new positions. Traditionally smoothing this required measuring each element’s start and end coordinates and manually animating the difference—a brittle approach that couples layout logic to animation code.
How Framer Motion’s layout Prop Works
The layout prop tells Framer Motion to monitor the element’s bounding box. On each render, if the box has moved, the library calculates the delta between the previous and new positions and applies a hardware‑accelerated transform (typically translate3d) to glide the element. This is the FLIP technique: First (record), Last (measure), Invert (apply opposite transform), Play (animate to identity). Because the animation runs on the compositor, the main thread is only involved in the initial measurement.
Shared Element Transitions with layoutId
When two different components should appear as a single visual entity—such as a thumbnail expanding into a full‑screen panel—give them the same layoutId. Framer Motion treats the unmounting component and the mounting component as the same element, animating between their respective sizes and positions. The result is a seamless morph without manual coordinate math.
Coordinating Multiple Animations with LayoutGroup
If several items in a list change position at the same time, each will start its own FLIP calculation. Without coordination, the browser may paint intermediate states that cause a brief “jump” as one element overtakes another. Wrapping the animating siblings in <LayoutGroup> tells Framer Motion to defer the start of all layout animations until every member has measured its new box, ensuring a synchronized, jump‑free transition.
Worked Example: A Reorderable List
The following snippet demonstrates a simple list where clicking a button shuffles the items. Each list item is a motion.li with the layout prop, and the whole list is inside a LayoutGroup.
import { motion, LayoutGroup } from 'framer-motion';
import { useState } from 'react';
export default function ShuffleList() {
const [items, setItems] = useState(['Apple', 'Banana', 'Cherry', 'Date']);
const handleShuffle = () => {
setItems([...items].sort(() => Math.random() - 0.5));
};
return (
Shuffle
{items.map((text) => (
{text}
))}
);
}
When the button is pressed, the items changes, causing React to re‑render the list with a new order. Because each motion.li has layout, Framer Motion measures the element’s old and new bounding boxes and animates the difference with a transform. The LayoutGroup ensures that all items begin their FLIP animation at the same frame, preventing any one item from appearing to “leap ahead” of its neighbors.
Trade‑offs and Limitations
- Main‑thread overhead: The FLIP technique requires a read of the element’s bounding box on every layout change. In lists with hundreds of items this can add measurable work to the render phase and may cause dropped frames if the budget is tight.
- CSS constraints: Elements that rely heavily on
transformfor their own styling, or that useposition: absolutewith offsets that change outside of Framer Motion’s control, can confuse the bounding‑box calculation and lead to visual glitches. - Need for stable keys: If the
keyprop on a moving element changes between renders, Framer Motion treats it as a new element and the layout animation is lost. Keep keys tied to a stable identifier (e.g., an ID from your data). - LayoutGroup size: While
LayoutGroupprevents jumps, it also means the group waits for the slowest member to finish measuring. Extremely large groups can therefore delay the start of the animation.
Verifying the Effect
Open the browser’s DevTools, select one of the list items, and click Shuffle. In the Elements panel you should see the transform property (e.g., translate3d(0px, 0px, 0px)) updating smoothly over the transition duration, while properties like top, left, or margin remain static. If the element snaps instantly, double‑check that the key is unchanged and that the layout prop is present on the motion component.
Actionable Closing
Start by adding layout to the moving children of any dynamic list or grid. Wrap those children in LayoutGroup when more than one element shifts at the same time. For shared‑element motions between unrelated components, give them a matching layoutId. Measure the impact with the browser’s performance panel; if you notice frame drops, consider limiting the animated subset or debouncing rapid reorders. This approach gives you smooth, physics‑based transitions without writing custom coordinate logic.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.