Blenra LogoBlenra
Web Components

Demystifying Framer Motion layoutId: Generating Shared Animations with AI

By Naveen Teja Palle5 min read
Demystifying Framer Motion layoutId: Generating Shared Animations with AI

The layoutId prop in Framer Motion is one of the most powerful and least understood features in modern React animation. When two components share the same layoutId, Framer Motion automatically animates between them — even if they're completely separate components in different parts of the component tree. This unlocks the "magic move" effect seen on Apple's iOS, the Vercel dashboard, and Linear's interface.

The problem is that layoutId is notoriously difficult to get right without understanding three core concepts: FLIP animation strategy, AnimatePresence boundaries, and cross-component state coordination. Without engineered prompts, the AI will generate code that almost works — but fails at the edges.

How layoutId Works Under the Hood

Framer Motion's layoutId uses the FLIP technique (First, Last, Invert, Play). When a component with a given layoutId unmounts and another with the same ID mounts, Framer Motion:

  1. Records the "First" position — the outgoing element's bounding box
  2. Records the "Last" position — the incoming element's final bounding box
  3. Inverts the transform — moves the incoming element to where the outgoing element was
  4. Plays — animates the element from the inverted position to its natural position

This happens in a single frame and feels entirely natural because it's the same visual element smoothly moving through space — even though React is mounting and unmounting completely different DOM nodes.

Prompt 1: Card-to-Expanded-Modal Layout Animation

The most common layoutId use case: clicking a card expands it into a full-screen modal with a smooth layout transition:

"Act as a Senior Framer Motion React Engineer. Create a TypeScript component system that demonstrates a card-to-full-screen modal expand animation using Framer Motion layoutId. Requirements: (1) A CardGrid component rendered a list of items, each as a <motion.div layoutId={'card-' + item.id}> with image, title, and subtitle. (2) Clicking a card sets selectedId in useState. (3) An AnimatePresence-wrapped overlay renders when selectedId is set, containing a <motion.div layoutId={'card-' + selectedId}> that expands to fill the viewport with a backdrop blur overlay. (4) The image inside the card must also have its own layoutId ('card-image-' + id) for independent image animation. (5) Close on backdrop click or ESC key. (6) Include proper exit animations using exit prop. No framer-motion version older than v10. Full TypeScript types."

Prompt 2: Tab Indicator Animation

The "sliding pill" tab indicator seen on Linear, Vercel, and Notion is a perfect layoutId use case:

"Write a React TypeScript tab navigation component using Framer Motion layoutId for the active tab indicator. Required behavior: (1) A horizontal tab list where the active tab is tracked in state. (2) A shared layoutId='active-tab' applied to a <motion.div> positioned absolutely within the active tab button — this creates the sliding pill/underline effect. (3) Use layout='position' on the indicator to only animate position, not size. (4) The transition must use type: 'spring', stiffness: 380, damping: 30 for a natural feel. (5) Each tab should have its own text color transition (inactive: gray-400, active: white). (6) Support both 'pill' variant (rounded background) and 'underline' variant (bottom border only). Export as a typed Tabs component with tab data as props."

Prompt 3: List-to-Detail Route Transition

In Next.js 14 with the App Router, animating across page routes with layoutId requires careful setup:

"Act as a Next.js 14 App Router expert. Implement cross-route shared layout animations using Framer Motion layoutId and the experimental ViewTransitions API. Create: (1) A /blog listing page where each post card has motion.div layoutId={'blog-' + post.id}. (2) A /blog/[slug] page where the hero image has the same layoutId as the card image. (3) A MotionConfig provider at the layout level with reducedMotion: 'user' to respect accessibility settings. (4) A custom page transition wrapper using AnimatePresence with mode='wait'. Explain the exact folder structure and which components need 'use client'. Include the framer-motion version and Next.js version this requires."

Common layoutId Pitfalls

⚠️ AnimatePresence Must Wrap Both Elements

The incoming and outgoing elements sharing a layoutId must exist within the same <AnimatePresence> boundary. If they're in separate AnimatePresence contexts, the layout animation won't trigger — the elements will simply appear/disappear without animating.

💡 Unique IDs Are Critical

If two different items accidentally share the same layoutId (e.g., using a hardcoded string instead of a unique item ID), Framer Motion will animate between the wrong elements. Always ensure your layoutId includes a unique identifier: `card-${item.id}` not just "card".

⚠️ SVGs and layout Prop

SVG elements don't support CSS layout animations the same way as div elements. If you need to animate SVGs with layoutId, wrap them in a motion div with the layoutId and let the SVG scale naturally within its container. Don't apply layoutId directly to <motion.svg> — it won't interpolate correctly for all SVG attributes.

Frequently Asked Questions

Q: Can I use layoutId with server components in Next.js App Router?

A: No. Framer Motion requires the DOM and JavaScript for its animations, so any component using motion components or layoutId must be a Client Component (marked with "use client"). You can wrap Server Components with Client Component wrappers that provide the animation layer.

Q: Why does my layoutId animation flicker on first render?

A: This is usually caused by a hydration mismatch in Next.js. The server renders the element in one position, then the client animates it from that position — but if the positions differ, you see a jump. Fix by ensuring the initial prop matches the server-rendered state, or by using suppressHydrationWarning on the parent element.

Q: Is layoutId compatible with Framer Motion's drag feature?

A: Yes, but with caveats. You can drag elements that have a layoutId. When the drag ends and the element snaps back, layoutId will animate it. However, combining drag and AnimatePresence-based layout animations in the same component can cause conflicts. Test thoroughly and use layout="position" instead of layout="true" for draggable elements.

NP

Naveen Teja Palle

Frontend Architect · Animation Engineer

React engineer with deep expertise in animation systems, Framer Motion, and building premium UX for SaaS products. Has shipped layoutId animations in multiple production applications.

500+ React Animation Prompts

Framer Motion, GSAP, React Spring, CSS animations — master every animation pattern with engineered AI prompts.

Explore Web Component Prompts →