How to Animate Page Transitions in React Router
Step-by-step guide to animating route transitions in React Router: AnimatePresence vs View Transitions API, scroll restoration, and avoiding DOM duplication.
Core Takeaway
To animate page transitions in React Router, use either the browser's native View Transitions API with startTransition() or wrap route outlets in Framer Motion's AnimatePresence using useLocation().key. Keep exit animations under 200ms to maintain snappy perceived performance, preserve scroll position correctly, and avoid rendering heavy duplicate trees in the DOM simultaneously.
The challenge of unmounting pages
React Router instantly unmounts the previous page component upon route change. For an exit animation to play, the exiting DOM elements must be held in the document tree until their transition finishes. Libraries like Framer Motion manage this via AnimatePresence by tracking the router's pathname key.
Native View Transitions API in React Router 6 and 7
React Router v6.4+ and v7 feature built-in support for the browser's View Transitions API via unstable_viewTransition or native link props. This mechanism captures a snapshot of the old page and animates to the new layout using pseudo-elements, eliminating the memory overhead of duplicate React component trees.
- Use document.startViewTransition() or Link viewTransition prop
- Keep page transition durations under 250ms for responsive navigation
- Animate shared headers and navigation bars persistently outside route outlets
- Always restore scroll position immediately on page change
Shared element transitions (morphing cards to details)
When navigating from a card grid to a detail page, animating the card expanding into the header creates powerful spatial context. The View Transitions API handles this natively via view-transition-name CSS properties matched between the list item and detail header.
Reduced motion and instant routing
Navigation should never make users feel trapped or dizzy. When prefers-reduced-motion is active, disable route transition animations completely so pages switch instantaneously.
Key Principles to Remember
- Keep page exit animations faster than enter animations (e.g. 150ms exit, 200ms enter)
- Adopt the View Transitions API to avoid memory bloat from concurrent route trees
- Keep persistent chrome (headers, navigation sidebars) outside the transition container
- Bypass route animations entirely under prefers-reduced-motion
Frequently Asked Questions
Sources
- View Transitions API — MDN Web Docs
- React Router View Transitions — Remix / Shopify