The idea
Drop <ClientRouter /> in your <head> and Astro turns every
in-site link into a single-page-app navigation with a morph animation — pair an element
across two pages with transition:name and the browser animates it from old position/size to new.
⚠ Renamed in Astro 5.0: the component was <ViewTransitions />
through Astro 4.x. In Astro 5.0 it was renamed to <ClientRouter />
(import from astro:transitions) to clarify that it is a client-side router, not just a fade.
Old tutorials still say ViewTransitions — that no longer exists in v5.
The transition demo — simulated A → B navigation
One .html can't change routes, so this swaps two page mockups inside the real
document.startViewTransition() — exactly what <ClientRouter /> does on a
route change. The "Penguins" card carries the paired name on both pages; watch it morph from
small (list, page A) to large (detail, page B). In real Astro, transition:name="hero-card"
compiles to the very view-transition-name: hero-card CSS used below.
API: …
current page: A (/) — list
paired name: hero-card
What the router does on each click
- Click an <a> (or back/forward)
- Router fetches the next page
- Calls document.startViewTransition() — browser screenshots the old page
- Inside the callback: swap <head> + <body>
- transition:persist elements are moved old → new DOM
- Paired view-transition-name elements morph A → B
- New scripts run, astro:page-load fires
No support? <ClientRouter fallback="swap|none" /> degrades gracefully
(default animate simulates the transition).
The three transition directives
<ClientRouter /> + the transition:* directives,
all riding the browser's View Transitions API. Cross-refs:
🔗 astro_routing_layouts (transitions fire on route change) ·
🔗 astro_islands (persist keeps an island alive across pages).