GlanceGlance
Back to Blog
Next.jsApril 2, 202614 min read

How to Add Page Transitions in Next.js App Router (2026 Guide)

Step-by-step guide to implementing smooth page transitions in Next.js 14/15 App Router using Framer Motion, GSAP, and CSS. Includes copy-paste examples for fade, slide, and cinematic transitions.

Share:

Page transitions are the difference between a website that feels like a collection of separate pages and one that feels like a cohesive product. This guide covers three approaches to adding page transitions in Next.js App Router — from simple CSS fades to cinematic GSAP reveals — with copy-paste code for each.

The challenge with Next.js App Router is that it doesn't support transitions natively. When a user navigates, the current page unmounts and the new page mounts instantly. To create smooth transitions, we need to intercept this process and animate between states.

Want ready-made transitions? Glance includes 15+ page transition animations for Next.js — fade, slide, clip-path reveals, curtain effects, and more. Preview them live and grab the code →

Approach 1: Framer Motion (Recommended)

Framer Motion's AnimatePresence component is purpose-built for animating components as they mount and unmount from the React tree. This makes it the most natural fit for Next.js page transitions.

Step 1: Create a Transition Template

In Next.js App Router, template.tsx re-renders on every navigation (unlike layout.tsx which persists). This is where we wrap page content with animation components.

// app/template.tsx
"use client"
import { motion } from "framer-motion"

export default function Template({ children }: { children: React.ReactNode }) {
  return (
    <motion.div
      initial={{ opacity: 0, y: 20 }}
      animate={{ opacity: 1, y: 0 }}
      transition={{ ease: "easeInOut", duration: 0.5 }}
    >
      {children}
    </motion.div>
  )
}

This gives you a fade-and-slide-up effect on every page navigation. The limitation is that template.tsx doesn't support exit animations because Next.js unmounts the page before the animation can play.

Step 2: Add Exit Animations with AnimatePresence

For true enter + exit transitions, you need a persistent layout component with AnimatePresence:

// components/page-transition.tsx
"use client"
import { AnimatePresence, motion } from "framer-motion"
import { usePathname } from "next/navigation"

export function PageTransition({ children }: { children: React.ReactNode }) {
  const pathname = usePathname()

  return (
    <AnimatePresence mode="wait">
      <motion.div
        key={pathname}
        initial={{ opacity: 0 }}
        animate={{ opacity: 1 }}
        exit={{ opacity: 0 }}
        transition={{ duration: 0.3 }}
      >
        {children}
      </motion.div>
    </AnimatePresence>
  )
}

// app/layout.tsx
import { PageTransition } from "@/components/page-transition"

export default function RootLayout({ children }) {
  return (
    <html>
      <body>
        <PageTransition>{children}</PageTransition>
      </body>
    </html>
  )
}

Approach 2: GSAP for Cinematic Transitions

When you need transitions that go beyond simple fades — curtain reveals, clip-path animations, staggered element exits — GSAP gives you frame-level control. This is the approach used by most Awwwards-winning Next.js sites.

// components/transition-overlay.tsx
"use client"
import { useEffect, useRef } from "react"
import gsap from "gsap"
import { usePathname } from "next/navigation"

export function TransitionOverlay() {
  const overlayRef = useRef<HTMLDivElement>(null)
  const pathname = usePathname()

  useEffect(() => {
    const tl = gsap.timeline()
    tl.set(overlayRef.current, { yPercent: -100 })
    tl.to(overlayRef.current, {
      yPercent: 0,
      duration: 0.5,
      ease: "power4.inOut",
    })
    tl.to(overlayRef.current, {
      yPercent: 100,
      duration: 0.5,
      ease: "power4.inOut",
      delay: 0.1,
    })
  }, [pathname])

  return (
    <div
      ref={overlayRef}
      className="fixed inset-0 z-50 bg-black pointer-events-none"
      style={{ transform: "translateY(-100%)" }}
    />
  )
}

This creates a black overlay that sweeps down and then up on every navigation — the classic curtain transition. Combine it with router.push() wrapped in a delay to let the exit animation complete before navigation.

Approach 3: CSS View Transitions API

The View Transitions API is a browser-native solution that requires zero JavaScript animation libraries. It works by capturing a screenshot of the current state, performing the DOM update, then crossfading between the two states. In 2026, it's supported in Chrome, Edge, and Safari.

// hooks/use-view-transition.ts
"use client"
import { useRouter } from "next/navigation"

export function useViewTransitionRouter() {
  const router = useRouter()

  const push = (href: string) => {
    if (!document.startViewTransition) {
      router.push(href)
      return
    }

    document.startViewTransition(() => {
      router.push(href)
    })
  }

  return { push }
}

// In your CSS:
// ::view-transition-old(root) { animation: fade-out 0.3s ease-out; }
// ::view-transition-new(root) { animation: fade-in 0.3s ease-in; }

This approach is the most lightweight but offers less control over complex animations.

Which Approach Should You Use?

Approach Best For Complexity Bundle Size
Framer Motion Most React/Next.js projects Low-Medium ~32KB gzipped
GSAP Awwwards-level cinematic effects Medium-High ~24KB gzipped
View Transitions API Simple fades, progressive enhancement Low 0KB (native)

Common Pitfalls

  • × Animating layout properties — always animate transform and opacity, never width/height/top/left.
  • × Forgetting cleanup — GSAP animations persist in memory. Always kill timelines in useEffect cleanup or useGSAP's auto-cleanup.
  • × Blocking navigation — if exit animations take too long (>500ms), users feel stuck. Keep transitions under 400ms for optimal UX.
  • × Wrapping in layout.tsx instead of template.tsx — layout.tsx persists across navigations, template.tsx re-mounts. Choose the right one for your animation strategy.

Get Production-Ready Transitions

Building page transitions from scratch takes hours of tweaking. Glance includes 15+ polished page transitions for Next.js — fade, slide, curtain, clip-path, and more. Preview any transition live, download the complete source code, and integrate it in minutes.

Browse Page Transitions on Glance →

Frequently Asked Questions

Does Next.js App Router support page transitions natively?

No. Next.js App Router does not include built-in page transition support as of 2026. The router unmounts and mounts page components immediately on navigation. To achieve smooth transitions, you need to use a third-party animation library like Framer Motion or GSAP, combined with a layout component that wraps page content and orchestrates enter/exit animations.

What is the best library for page transitions in Next.js?

Framer Motion is the most popular choice because its AnimatePresence component is designed specifically for mount/unmount animations in React. GSAP is more powerful for complex, multi-step transitions (like the cinematic reveals seen on Awwwards sites). For simple fade transitions, CSS animations with View Transitions API are the lightest option.

How do I prevent layout shift during page transitions in Next.js?

Use position: fixed or position: absolute on the exiting page component during the exit animation. This takes it out of the document flow so the entering page can render underneath. In Framer Motion, set mode='wait' on AnimatePresence to finish the exit before starting the enter. Also ensure your layout.tsx wraps the transition — not individual page.tsx files.

Do page transitions hurt SEO in Next.js?

No, if implemented correctly. Since Next.js renders pages server-side before hydration, search engine crawlers see the full page content regardless of client-side transitions. The transitions only affect the visual experience after JavaScript loads. Ensure your content is in the SSR output and that transitions don't delay Largest Contentful Paint (LCP).

Can I use the View Transitions API with Next.js?

The View Transitions API is a browser-native feature that enables smooth transitions between DOM states. As of 2026, it works in Chrome and Edge. You can use it with Next.js by calling document.startViewTransition() in your router navigation handler. However, browser support is not universal, so consider it a progressive enhancement alongside a Framer Motion or GSAP fallback.

How do I add page transitions to Next.js with Framer Motion?

Create a template.tsx file in your app directory that wraps children with Framer Motion's AnimatePresence and motion.div components. Use initial, animate, and exit props to define the transition states. The key prop should be set to the current pathname (from usePathname) so Framer Motion detects route changes and triggers the animation cycle.

Stop building animations from scratch

130+ production-ready animations for React, Next.js, and Vanilla JS. Preview live, grab the code, ship it. Starts at $3.99.

Browse the Animation Library →