View Transitions
moco/view-transitionsFreeComponent
Cross-fade View Transitions for Next.js App Router route changes, plus a no-js flag remover.
Live preview
live · rendered by the registry
Rendered by moco on their own page — this is the component running, not a screenshot of it.Install it
npx shadcn@latest add https://mocoui.site/r/view-transitions.jsonSource
1"use client";23import * as React from "react";4import { useRouter } from "next/navigation";5import "./view-transitions.css";67/**8 * View Transitions for client-side route changes (Next.js App Router only).9 * Feature-detected, and a complete no-op where unsupported or under10 * prefers-reduced-motion.11 *12 * ponytail: the transition is closed on a short timer rather than on the13 * router's commit, because App Router does not expose a navigation-complete14 * promise. Swap the timer for that promise if/when Next exposes one.15 */16export function ViewTransitions() {17 const router = useRouter();1819 React.useEffect(() => {20 const doc = document as Document & {21 startViewTransition?: (cb: () => void | Promise<void>) => unknown;22 };23 if (typeof doc.startViewTransition !== "function") return;24 if (window.matchMedia("(prefers-reduced-motion: reduce)").matches) return;2526 const onClick = (e: MouseEvent) => {27 if (e.defaultPrevented || e.button !== 0 || e.metaKey || e.ctrlKey || e.shiftKey || e.altKey)28 return;29 const a = (e.target as HTMLElement | null)?.closest?.("a");30 if (!a || a.target === "_blank" || a.hasAttribute("download")) return;31 const url = new URL(a.href, location.href);32 if (url.origin !== location.origin) return;33 if (url.pathname === location.pathname) return;3435 e.preventDefault();36 doc.startViewTransition!(async () => {37 router.push(url.pathname + url.search + url.hash);38 await new Promise((r) => setTimeout(r, 90));39 });40 };4142 document.addEventListener("click", onClick);43 return () => document.removeEventListener("click", onClick);44 }, [router]);4546 return null;47}4849/** Removes the `no-js` class so JS-only affordances can hide their fallbacks. */50export function JsFlag() {51 React.useEffect(() => {52 document.documentElement.classList.remove("no-js");53 }, []);54 return null;55}
What it pulls in
npm packages
Other registry items
Files it writes
More from moco
All 20 items| Component | Registry | Kind | Access | Installs | Command |
|---|---|---|---|---|---|
| Codecode | moco | Components | Free | 1 dep · 3 files | |
| Comparecompare | moco | Components | Free | no deps · 2 files | |
| Count Upcountup | moco | Components | Free | no deps · 2 files | |
| Covercover | moco | Components | Free | no deps · 2 files | |
| Diagram Kitdiagram | moco | Components | Free | no deps · 2 files | |
| Dot Griddotgrid | moco | Components | Free | no deps · 2 files | |
| Figurefigure | moco | Components | Free | no deps · 2 files | |
| Hookshooks | moco | Components | Free | no deps |
