Page Transition Wrapper
Wraps route content so it animates out and the next page animates in instead of swapping instantly.
- Category
- Animations
- Added
- 2026-09-01
- Deps
- 1
- Updated
- 2026-09-01
This is a viberdy Pro component
The live preview, the props panel and the write-up are open to everyone. The full source, the AI prompt and CLI install are part of Pro.
Home page
Props
"use client";
import { AnimatePresence, motion, useReducedMotion } from "framer-motion";
import type { ReactNode } from "react";
const VARIANTS = {
fade: { initial: { opacity: 0, x: 0, scale: 1 }, exit: { opacity: 0, x: 0, scale: 1 } },
slide: { initial: { opacity: 0, x: 24, scale: 1 }, exit: { opacity: 0, x: -24, scale: 1 } },
scale: { initial: { opacity: 0, x: 0, scale: 0.96 }, exit: { opacity: 0, x: 0, scale: 1.03 } },
} as const;
export function PageTransitionWrapper({
children,
transitionKey,
variant = "slide",
duration = 0.35,
}: {
children: ReactNode;
// ---------------------------------------------------------------
// Full source available with a viberdy Pro subscription.
// https://viberdy.dev/pricing
// ---------------------------------------------------------------
}About this animation
Page Transition Wrapper animates opacity plus one transform (an x translate or a scale, depending on variant) between two full page-level nodes — never top/left/width, which would force layout across the whole page on every frame. Reach for this instead of a bare CSS transition because a route swap replaces the DOM node entirely; CSS transitions cannot animate an element that's about to unmount and be replaced by an unrelated one, but AnimatePresence keeps the outgoing node mounted just long enough to finish its exit animation before removing it. The non-obvious detail is mode=\"wait\": it's what makes the effect read as one continuous wipe rather than a cross-fade, because it holds the incoming page's enter animation until the outgoing page has fully exited, rather than running both at once. The caveat: every page passed through this wrapper needs a stable, unique key (in practice the route pathname) — without it React treats unrelated pages as the same instance and silently skips the transition.
Pairs well with
Matched on shared tags and category — the entries most likely to be used alongside this one.
Stagger Reveal Group
animationsA wrapper that reveals its children one after another as the group scrolls into view.
Line Mask Reveal
animationsReveals text one line at a time, each sliding up from behind its own clipping mask.
Pointer Parallax Scene
animationsA depth system where layers separate under the pointer from one shared motion source.