Page Navigation

By Syncfusion®, Inc. · Last updated

Full page loads vs client-side navigation, the ClientRouter component, transition:name and transition:animate, transition:persist for islands, scripts and the astro:page-load event, navigate(), data-astro-reload and prefetching strategies. Checkpoint 3.

Page Navigation

  • By default, each link click loads a whole new page.
  • The browser throws the old page away and builds the new one.
  • That is simple and reliable, but the screen flashes and any state is lost.
  • Astro's ClientRouter swaps pages smoothly instead, with animated view transitions.
  • In this lesson, you will turn on the router, animate elements between pages, keep islands alive, and make links load early.

Simple lesson: ClientRouter swaps pages without a full reload, so navigation feels smooth.

A Real-World Example

  • Asha's journal has a header, a post list and post pages.
  • Every click flashes white, and the music player in her header restarts.
  • She adds <ClientRouter /> to her layout once.
  • Now the pages slide in, the header stays still, and the player keeps playing.

Press ▶ Run. Click About and Home a few times. The Terminal shows each page being swapped, not reloaded.

What happened:

  • <ClientRouter /> added a small script to every page that uses this layout.
  • On a link click, the router fetched the new page and swapped the content in place.
  • The browser's View Transitions feature animated the change.

What You Will Learn

In this lesson, you will learn:

  1. Full page loads vs client-side navigation.
  2. How to add <ClientRouter />.
  3. How to match elements between pages with transition:name.
  4. How to choose animations with transition:animate.
  5. How to keep an element alive with transition:persist.
  6. How scripts behave with the router, and the astro:page-load event.
  7. How to navigate from code with navigate().
  8. How to prefetch pages before the click.

Full Loads vs ClientRouter

What Happens on a Click

Animation: on the left, a full page load blanks the whole screen before the new page appears. On the right, the ClientRouter keeps the header and swaps only the main content. Full page load

header (rebuilt) everything rebuilt ClientRouter

header (kept)

only main swaps

Left: the whole page blinks. Right: only the changed part slides.

  • Full page load (the default): simple, works everywhere, but flashes and loses state.
  • ClientRouter: smooth, keeps what you ask it to keep, adds a little JavaScript.
  • If a browser has no View Transitions support, the router still swaps pages, with a simple fallback animation.

Adding the Router

  1. Import it in the frontmatter: import { ClientRouter } from "astro:transitions";
  2. Put <ClientRouter /> inside <head>.
  3. Put it in your layout, so every page has it.
  • A page without the router does a full load when you leave it or arrive at it.
  • To force a full load for one link, add data-astro-reload: <a href="/admin" data-astro-reload>.

In Astro 4 the component was called <ViewTransitions />. In Astro 5 and later it is <ClientRouter />.

Simple lesson: put <ClientRouter /> in the layout's <head> to turn on smooth navigation.

Animating Between Pages

Matching Elements with transition:name

  • By default, the router fades the old page out and the new page in.
  • Give an element on two pages the same transition:name, and the browser morphs one into the other.
  • Example: the post title in the list grows into the big heading on the post page.

Choosing an Animation with transition:animate

ValueEffect
fade (default)Old fades out, new fades in
slideOld slides out left, new slides in from the right
initialThe browser's own default cross-fade
noneNo animation for this element
fade({ duration: "0.6s" })Fade with your own timing

Press ▶ Run. Click a post title. The title morphs into the heading, and the main area slides.

  • Each transition:name must be unique on a page, so the names include the slug.

Astro turns animations off for readers who set "reduce motion" in their system settings (prefers-reduced-motion). You do not need extra code for that.

Simple lesson: transition:name links an element across two pages. transition:animate picks the effect.

Keeping Things Alive

transition:persist

  • Normally the router replaces everything inside <body>.
  • transition:persist tells it: keep this exact element, do not replace it.
  • Use it for an audio player, a video, or an island whose state must survive the trip.
  • Give it a name when the element is on different pages: transition:persist="player".

Press ▶ Run. Click +1 three times, then go to About. The count stays at 3.

  • Remove transition:persist="counter" and try again. The count resets on every page.

Simple lesson: transition:persist keeps an element, and its state, across page swaps.

Scripts and Router Events

Scripts Run Only Once

  • With full page loads, a processed <script> runs on every page load.
  • With the router, the page is not reloaded. A processed script runs once, the first time.
  • So code that finds elements on the page must run again after each swap.

The astro:page-load Event

  • The router fires astro:page-load after every navigation, and on the first load too.
  • Put page setup code in a listener for it.
EventWhen it fires
astro:before-preparationA navigation starts, before the new page is fetched
astro:before-swapJust before the old page is replaced
astro:after-swapJust after the new page is in place
astro:page-loadThe new page is ready (also on the first load)

Press ▶ Run. Move between pages and press Say hi on each one. It works every time because the listener is set up in astro:page-load.

  • [JS] Leave out the ! after getElementById(...).
  • To run a whole script again after each swap instead, add data-astro-rerun to an is:inline script.

A click listener added outside astro:page-load is attached to the first page's button only. After a swap, the new button has no listener, so it silently does nothing.

Simple lesson: with the router, set up pages inside an astro:page-load listener.

Navigating from Code and Prefetching

navigate()

  • Sometimes code must change the page, for example after a select box changes.
  • navigate(url) from astro:transitions/client does a router navigation, with animations.

Prefetching

  • Prefetching loads a page in the background before the click, so it opens almost instantly.
  • With <ClientRouter />, prefetching is on. Without it, set prefetch: true in astro.config.mjs.
  • Mark a link with data-astro-prefetch. Choose when it loads:
StrategyPrefetch when
hover (default)The mouse is over the link, or it gets keyboard focus
tapJust before the click
viewportThe link scrolls into view
loadThe page has loaded
  • prefetch: { prefetchAll: true } prefetches every link. data-astro-prefetch="false" turns one off.

Press ▶ Run. The Terminal shows two links prefetched on load. Move the mouse over Hover me to prefetch it. Then pick a page in the select box.

  • [JS] Leave out as HTMLSelectElement | null.

Prefetch only links people are likely to click. prefetchAll on a page with 200 links downloads 200 pages.

Simple lesson: navigate() moves pages from code. Prefetching loads likely pages before the click.

Checkpoint 3

  • You can now build interactive Astro sites:

    • islands with the right client:* directive,
    • shared state between islands,
    • smooth navigation with <ClientRouter />,
    • persistent elements and router events,
    • prefetching.
  • Try this: give Asha's journal a persistent "reading list" island in the header that keeps its items as you move between posts.

TL;DR

  1. Default = full page load on every click.
  2. ClientRouter = <ClientRouter /> in the layout <head>. Pages swap without a full reload.
  3. transition:name = links an element on two pages, so it morphs.
  4. transition:animate = fade, slide, initial, none, or fade({ duration }).
  5. transition:persist = keep this element (and island state) across swaps.
  6. Scripts = run once with the router. Put page setup in astro:page-load.
  7. navigate(url) = router navigation from code.
  8. Prefetch = data-astro-prefetch with hover, tap, viewport or load.
  9. data-astro-reload = force a full load for one link.

Common mistakes

MistakeWrong ideaCorrect ideaWhat goes wrong
<ClientRouter /> on one page onlyIt works for the whole sitePut it in the shared layoutSome clicks still do full loads
Setup code outside astro:page-loadScripts run on every pageProcessed scripts run onceButtons stop working after a swap
The same transition:name twice on a pageNames can repeatEach name is unique per pageThe animation breaks
No transition:persist on a playerThe router keeps everythingIt replaces the bodyMusic and island state reset
Using <ViewTransitions />It is the current nameIt is <ClientRouter /> nowImport error
prefetchAll on huge pagesMore prefetching is always fasterPrefetch likely links onlyWasted data

Check Yourself

Exercises

What to Remember

  • Astro does full page loads by default. <ClientRouter /> in the layout makes them smooth swaps.
  • transition:name morphs matching elements. transition:animate picks the effect.
  • transition:persist keeps elements and island state alive.
  • With the router, scripts run once: use astro:page-load for page setup.
  • navigate() moves from code. data-astro-prefetch loads pages before the click.

Next: Endpoints and Server Data, where your site starts to answer requests with data.