Terminal
1npm install framer-motion
The FrozenRouter pattern solves the 'flickering' content problem during exit animations in Next.js App Router. Context freezing keeps old content visible until the animation completes.
npm install framer-motionFrozenRouter to preserve content during exitAnimatePresence mode="wait" sequences enter/exit1npm install framer-motion
1'use client'23import { AnimatePresence, motion } from 'framer-motion'4import { usePathname } from 'next/navigation'5import { LayoutRouterContext } from 'next/dist/shared/lib/app-router-context.shared-runtime'6import { useContext, useRef, ReactNode } from 'react'78function FrozenRouter({ children }: { children: ReactNode }) {9 const context = useContext(LayoutRouterContext)10 const frozen = useRef(context).current1112 return (13 <LayoutRouterContext.Provider value={frozen}>14 {children}15 </LayoutRouterContext.Provider>16 )17}1819export function PageTransition({ children }: { children: ReactNode }) {20 const pathname = usePathname()2122 return (23 <AnimatePresence mode="wait">24 <motion.div25 key={pathname}26 initial={{ opacity: 0, y: 20, scale: 0.98 }}27 animate={{ opacity: 1, y: 0, scale: 1 }}28 exit={{ opacity: 0, y: -20, scale: 0.98 }}29 transition={{30 duration: 0.3,31 ease: [0.25, 0.46, 0.45, 0.94],32 }}33 >34 <FrozenRouter>{children}</FrozenRouter>35 </motion.div>36 </AnimatePresence>37 )38}
1import { PageTransition } from './page-transition'23export default function Layout({ children }: { children: React.ReactNode }) {4 return <PageTransition>{children}</PageTransition>5}