Enable viewTransitions in Next config.
Next.js: experimental.viewTransition
import type { NextConfig } from "next";
const nextConfig: NextConfig = {
experimental: {
viewTransition: true,
},
};
export default nextConfig;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.
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>
);
}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).
::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);
}
}Add transitionTypes that match a key in your layout map (here slide-left).
import Link from "next/link";
export default function Home() {
return (
<Link href="/about" transitionTypes={["slide-left"]}>
About
</Link>
);
}Add transitionTypes for the return navigation with a different type (slide-right).
import Link from "next/link";
export default function AboutPage() {
return (
<Link href="/" transitionTypes={["slide-right"]}>
Home
</Link>
);
}