Skip to content

Conversation

Samii2383
Copy link
Contributor

…This PR adds a new example at examples/with-framer-motion-app-router that demonstrates shared element transitions with Framer Motion using the Next.js App Router, without hydration warnings.
What’s included:
app/template.tsx as a client transition boundary with LayoutGroup + AnimatePresence.
All motion-rendering surfaces are client components ('use client').
Route transitions keyed by usePathname() and initial={false} to avoid SSR/CSR diffs.
Shared element via matching layoutId across routes.
Minimal pages (/ grid → /[slug] detail), with a concise README.
Why:
Addresses common pitfalls when combining App Router and Framer Motion shared layout transitions that can cause hydration mismatch warnings or janky transitions.
Provides a canonical setup developers can copy into their projects.
Test plan:
cd examples/with-framer-motion-app-router
pnpm install && pnpm dev
Navigate between / and /[slug] and verify:
Smooth shared element transitions
No hydration warnings in dev or prod build
Notes:
Add three images under public/photos/1.jpg, public/photos/2.jpg, public/photos/3.jpg (or adjust the example data) to see the visuals.
Example depends on framer-motion@^11 and Next canary.
References:
Upstream repo: https://github.com/vercel/next.js
Your fork/branch: https://github.com/Samii2383/next.js (branch: feat/examples-with-framer-motion-app-router)
Open PR link: https://github.com/vercel/next.js/compare/canary...Samii2383:feat/examples-with-framer-motion-app-router?expand=1
Logic explained (how the example avoids hydration issues)
Client transition boundary: app/template.tsx is a client component and wraps page content in LayoutGroup + AnimatePresence. This ensures the transition logic only runs on the client, preventing SSR-side animation state from leaking into the server render.
Stable route key: We key the transition container by usePathname(), so React tears down and mounts the motion container predictably for each navigation. This keeps Framer Motion’s enter/exit lifecycle consistent.
initial={false}: AnimatePresence uses initial={false} so the first client paint doesn’t replay an “enter” animation over the server-rendered markup. That’s the most common cause of hydration diffs with animations.
Shared element (layoutId): The grid and detail views use identical layoutId values for the same visual element, letting Framer Motion interpolate geometry between routes.
Client-only motion surfaces: Grid, Detail, and SharedImage are marked 'use client'. Framer Motion’s DOM measurement and animation occur only on the client, avoiding any server vs client markup divergence.
Next/Image sizing: The shared image uses sizes and fixed width/height to reduce layout shifts, which further cuts down on noisy DOM diffs during hydration.

… Framer Motion example without hydration warnings
@ijjk ijjk added the examples Issue was opened via the examples template. label Oct 16, 2025
@ijjk
Copy link
Member

ijjk commented Oct 16, 2025

Allow CI Workflow Run

  • approve CI run for commit: 3494d5d

Note: this should only be enabled once the PR is ready to go and can only be enabled by a maintainer

@Samii2383
Copy link
Contributor Author

This only adds an example under examples/, no core changes. Ready for CI. If anything fails, I’ll adjust the example to match examples conventions

@Samii2383
Copy link
Contributor Author

Hi team 👋
This PR only adds a new example under examples/ (no core changes).
All client components are isolated and follow existing conventions.
Failing CI checks seem unrelated to the example build — happy to update if any adjustments are needed.

Thanks for reviewing! 🙏

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

examples Issue was opened via the examples template.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants