All skills
Skillintermediate

View Transitions in Next.js

`` works out of the box for `startTransition`/`Suspense` updates. To also animate `` navigations:

Claude Code Knowledge Pack7/10/2026

Overview

View Transitions in Next.js

Setup

works out of the box for `startTransition`/`Suspense` updates. To also animate navigations:

// next.config.js
const nextConfig = {
  experimental: { viewTransition: true },
};
module.exports = nextConfig;

This wraps every `` navigation in document.startViewTransition. Any VT with default="auto" fires on every link click — use default="none" to prevent competing animations.

Requires react@canary: npm install react@canary react-dom@canary


Next.js Implementation Additions

When following implementation.md, apply these additions:

After Step 2: Enable the experimental flag above.

Step 4: Use transitionTypes on `` instead of manual addTransitionType:

View
Back

Reserve startTransition + addTransitionType for programmatic navigation (buttons, forms).

After Step 6: For same-route dynamic segments (e.g., /collection/[slug]), use the key + name + share pattern — see Same-Route Dynamic Segment Transitions below.


Layout-Level ViewTransition

Do NOT add a layout-level VT wrapping {children} if pages have their own VTs. Both fire simultaneously, producing competing animations.

A bare `` in layout works only if pages have no VTs of their own. Once any page adds a VT, use default="none" on the layout VT or remove it.

Layouts persist across navigationsenter/exit only fire on initial mount, not on route changes. Don't use type-keyed maps in layouts.

// Prevents layout from interfering with per-page VTs
{children}

The transitionTypes Prop on next/link

Native prop — no wrapper component needed, works in Server Components:

View Product

Replaces the manual pattern of onNavigate + startTransition + addTransitionType + router.push(). Reserve manual startTransition for non-link interactions (buttons, forms).


Programmatic Navigation

'use client';

function handleNavigate(href: string) {
  const router = useRouter();
  startTransition(() => {
    addTransitionType('nav-forward');
    router.push(href);
  });
}

Directional Navigation

Place type-keyed VTs in page components (not layouts):


  

Two-Layer Pattern

Directional slides + Suspense reveals coexist because they fire at different moments:


  <div>
    }>
      
    
  </div>


Shared Elements Across Routes

// List page
{products.map((product) => (
  
    
      
    
  
))}

// Detail page — same name

  


Same-Route Dynamic Segment Transitions

When navigating between dynamic segments of the same route (e.g., /collection/[slug]), the page stays mounted — enter/exit never fire. Use key + name + share:

}>
  
    
  

  • key={slug} forces unmount/remount on change
  • name + share="auto" creates a shared element crossfade
  • VT inside `` (without keying Suspense) keeps old content visible during loading

Suspense and Loading States

}>
  

Don't combine with a layout-level VT using default="auto".


Server Components

  • `` works in both Server and Client Components
  • `` works in Server Components — no 'use client' needed
  • addTransitionType and startTransition for programmatic nav require Client Components