Skip to content

Instantly share code, notes, and snippets.

@SidKH
Last active March 20, 2026 21:44
Show Gist options
  • Select an option

  • Save SidKH/a9d9faf5f72278a4b500efefc9ff0967 to your computer and use it in GitHub Desktop.

Select an option

Save SidKH/a9d9faf5f72278a4b500efefc9ff0967 to your computer and use it in GitHub Desktop.
Next.js Link transitionTypes + ViewTransition: files to copy

How to apply different transition types to navigation in Next.js 16.2

next.config.ts

Enable viewTransitions in Next config.

Next.js: experimental.viewTransition

import type { NextConfig } from "next";

const nextConfig: NextConfig = {
  experimental: {
    viewTransition: true,
  },
};

export default nextConfig;

app/layout.tsx

Wrap children in ViewTransition. Map each transition type string to a CSS class for your ::view-transition-* rules. Keep default: "none" so only named types animate.

React: ViewTransition

import { ViewTransition } from "react";
import "./globals.css";

export default function RootLayout({
  children,
}: Readonly<{
  children: React.ReactNode;
}>) {
  return (
    <html lang="en">
      <body>
        <ViewTransition
          default={{
            default: "none",
            fade: "fade",
            "slide-left": "slide-left",
            "slide-right": "slide-right",
          }}
        >
          {children}
        </ViewTransition>
      </body>
    </html>
  );
}

Global CSS (e.g. app/globals.css)

Add ::view-transition-group / ::view-transition-old / ::view-transition-new rules for each class you mapped in ViewTransition, plus matching @keyframes. Fade plus slide-left / slide-right (used by the page examples below).

MDN: View Transition API

::view-transition-group(.fade),
::view-transition-group(.slide-left),
::view-transition-group(.slide-right) {
  animation-duration: 420ms;
  animation-timing-function: cubic-bezier(0.16, 1, 0.3, 1);
}

::view-transition-old(.fade) {
  animation-name: demo-fade-out;
}

::view-transition-new(.fade) {
  animation-name: demo-fade-in;
}

::view-transition-old(.slide-left) {
  animation-name: demo-slide-left-out;
}

::view-transition-new(.slide-left) {
  animation-name: demo-slide-left-in;
}

::view-transition-old(.slide-right) {
  animation-name: demo-slide-right-out;
}

::view-transition-new(.slide-right) {
  animation-name: demo-slide-right-in;
}

@keyframes demo-fade-out {
  from {
    opacity: 1;
  }
  to {
    opacity: 0;
  }
}

@keyframes demo-fade-in {
  from {
    opacity: 0;
  }
  to {
    opacity: 1;
  }
}

@keyframes demo-slide-left-out {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(-100vw);
  }
}

@keyframes demo-slide-left-in {
  from {
    transform: translateX(100vw);
  }
  to {
    transform: translateX(0);
  }
}

@keyframes demo-slide-right-out {
  from {
    transform: translateX(0);
  }
  to {
    transform: translateX(100vw);
  }
}

@keyframes demo-slide-right-in {
  from {
    transform: translateX(-100vw);
  }
  to {
    transform: translateX(0);
  }
}

app/page.tsx

Add transitionTypes that match a key in your layout map (here slide-left).

Next.js: Link transitionTypes

import Link from "next/link";

export default function Home() {
  return (
    <Link href="/about" transitionTypes={["slide-left"]}>
      About
    </Link>
  );
}

app/about/page.tsx

Add transitionTypes for the return navigation with a different type (slide-right).

Next.js: Link transitionTypes

import Link from "next/link";

export default function AboutPage() {
  return (
    <Link href="/" transitionTypes={["slide-right"]}>
      Home
    </Link>
  );
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment