The world of web development has long been divided into two camps.
On one side, the Static Site (MPA - Multi-Page Application) purists: unbeatable loading times, perfect SEO, but a white “flash” at every page change because the browser destroys and recreates the entire DOM. On the other, the fans of the Single Page Application (SPA) with React, Vue, or Angular: ultra-smooth navigation without reloading, but at the cost of a heavy JavaScript bundle to download and increased complexity.
What if I told you that with Astro, you can have your cake and eat it too? A 100% server-side generated static site that behaves exactly like a fluid client-side SPA.
The magic lies in a single component: <ClientRouter />.
How does it work?
Astro relies on a recent browser technology called the View Transitions API.
Rather than letting the browser brutally reload the entire page when a link is clicked, Astro intercepts this click. It fetches the HTML of the new page in the background, then intelligently “merges” the old DOM with the new one, animating the transition between the two.
The result? The user gets the perfect illusion of navigating within an application, even though they are browsing simple static HTML files.
The Implementation (literally 2 lines of code)
This is where Astro’s developer experience shines. To enable this feature across your entire site, you just need to modify your <head> tag.
If you have followed my previous articles, you know that I use a BaseHead.astro component common to all my pages. This is where the magic happens:
---
// src/components/BaseHead.astro
import { ClientRouter } from 'astro:transitions';
const { title, description } = Astro.props;
---
<head>
<meta charset="utf-8" />
<title>{title}</title>
<meta name="description" content={description} />
<ClientRouter />
</head>
And… that’s it. Now browse your site: the brutal reload is gone, replaced by a subtle crossfade by default. The state of your page (like the scroll position or a playing video) can even be preserved between navigations!
The Catch: The JavaScript Lifecycle
While the visual illusion is perfect, it is also perfect for your Vanilla JavaScript code.
Since the browser no longer performs a true “page reload”, classic events like DOMContentLoaded or window.onload will no longer fire when the user navigates from one article to another.
If you have scripts to manage a mobile menu, a carousel, or, as we saw recently, an AJAX contact form, they might only work on the first page visited.
Fortunately, Astro anticipated this by replacing these native events with its own. Instead of listening to the classic DOM load, you must now listen to the astro:page-load event:
// Before (Will only work on the first site load)
document.addEventListener('DOMContentLoaded', () => {
initMyMobileMenu();
});
// With ClientRouter (Will work on every page change)
document.addEventListener('astro:page-load', () => {
initMyMobileMenu();
});
Conclusion
The integration of the ClientRouter in Astro is a true Game Changer. By simply adding two lines of code, you offer your visitors a premium experience, worthy of the biggest web applications, while maintaining a simple, lightweight, and performant architecture.
It’s a total victory for UX and developers. Be careful, however, to review your JavaScript scripts so they survive this new fluidity (we’ll actually talk about the mobile menu trap in an upcoming article!).