Overlays & Feedback

Page Transition

A route transition container combining View Transitions concepts with overlay reveals, playing one of four transitions — fade, slide, cover, or wipe — whenever the route changes.

This is a WebberUI Pro component

The install command below needs a licence to run; without one it returns 401.

How to install Pro components →See the plans →

Bring this into your project

Run this command in your project folder. The CLI adds the source and dependencies; then follow the usage example below.

npx webberui@latest add "https://webberui.com/r/page-transition.en.json?t=<install token>"

New project or installation trouble? Start here →

Playground

Tune the props live — the code snippet updates as you go, so you can dial in the look you want before copying it.

0.6
24
Active edited usageDefault props
<PageTransition/>

The complete example includes the preview layout and data. Install the component first, then paste this file into your project.

Installation

npx webberui@latest add "https://webberui.com/r/page-transition.en.json?t=<install token>"

Or, once registries are configured in components.json, install it as @webberui/page-transition.

Usage

Wrap your page content in PageTransition and pass the value that changes with the route (usually the pathname) to transitionKey. In the Next.js App Router, the most natural place for this is template.tsx:

"use client";

import { usePathname } from "next/navigation";
import { PageTransition } from "@/components/ui/page-transition";

export default function Template({ children }: { children: React.ReactNode }) {
  const pathname = usePathname();

  return (
    <PageTransition transitionKey={pathname} variant="cover" direction="right">
      {children}
    </PageTransition>
  );
}

Native View Transitions

If you want navigation to trigger the browser's native View Transitions (cross-page crossfades, shared-element morphs), wrap the update that changes the DOM with useViewTransition:

"use client";

import { useRouter } from "next/navigation";
import { useViewTransition } from "@/components/ui/page-transition";

export function NavLink({ href, children }: { href: string; children: React.ReactNode }) {
  const router = useRouter();
  const startTransition = useViewTransition();

  return (
    <a
      href={href}
      onClick={(event) => {
        event.preventDefault();
        startTransition(() => router.push(href));
      }}
    >
      {children}
    </a>
  );
}

Browsers without View Transitions support simply run the update directly, degrading gracefully.

Props

PageTransition

PropTypeDefaultDescription
childrenReact.ReactNode—Page content
transitionKeystring | number—The transition trigger key; changing it plays the transition once (usually the pathname)
variant"fade" | "slide" | "cover" | "wipe""fade"Transition style
direction"up" | "down" | "left" | "right""up"Direction of the offset or the cover sweep
durationnumber0.6Total duration of the whole transition (seconds), split evenly between exit and enter
distancenumber24Offset distance for the slide variant (px)
overlayClassNamestring—Appended to the overlay className (cover / wipe), so you can override its background color
classNamestring—Appended to the outer container className
onTransitionComplete() => void—Callback fired when the transition has completely finished

useViewTransition()

Returns startTransition(update), where update is a function that changes the DOM (either synchronous or returning a Promise), and the return value is a Promise<void> that resolves when the transition ends.

How it works

  • State-machine driven: internally it runs a three-stage state machine — exit → swap the content seamlessly at the peak of the cover → enter — advanced entirely by Motion's onAnimationComplete, with no timers involved.
  • Overlay reveal: cover slides a solid panel in to cover, then slides it out from the opposite side to reveal; wipe sweeps across by scaling along the axis, switching transform-origin automatically between covering and revealing. The content swap happens at the exact moment the panel fully covers the view, so nothing visible jumps.
  • No animation on first load: the initial render matches the SSR output, and a transition only plays after transitionKey changes.
  • Rapid successive changes: changing transitionKey again mid-transition jumps straight to the newest content once the current transition ends, rather than stacking up playbacks.

Accessibility

  • When the user has "reduce motion" enabled at the system level, the content is swapped instantly with no offset or cover animation played at all.
  • While a transition is running the outer container carries aria-busy, and the overlay is hidden from assistive technology with aria-hidden and is pointer-events-none so it does not intercept interaction.