Astro's View Transitions is a powerful feature that enables smooth page switching experiences similar to Single Page Applications (SPAs) while maintaining the performance benefits of static sites.
Core Concepts:
View transitions use the browser's native View Transitions API to provide smooth visual transitions during page navigation.
Basic Usage:
astro--- // src/layouts/Layout.astro import { ViewTransitions } from 'astro:transitions'; --- <html> <head> <title>My Website</title> <ViewTransitions /> </head> <body> <slot /> </body> </html>
Transition Types:
-
Fade:
astro<ViewTransitions transition="fade" /> -
Slide:
astro<ViewTransitions transition="slide" /> -
None:
astro<ViewTransitions transition="none" />
Custom Transitions:
astro--- // src/layouts/Layout.astro import { ViewTransitions } from 'astro:transitions'; --- <html> <head> <title>My Website</title> <ViewTransitions /> <style is:global> ::view-transition-old(root), ::view-transition-new(root) { animation-duration: 0.5s; } @keyframes custom-fade { from { opacity: 0; transform: translateY(20px); } to { opacity: 1; transform: translateY(0); } } ::view-transition-new(root) { animation: custom-fade 0.5s ease-out; } </style> </head> <body> <slot /> </body> </html>
Shared Element Transitions:
astro--- // src/pages/index.astro import { transition } from 'astro:transitions'; --- <h1 transition:name="hero-title">Welcome to My Website</h1> <img src="/hero.jpg" alt="Hero Image" transition:name="hero-image" /> <a href="/about" transition:name="cta-button">Learn More</a>
astro--- // src/pages/about.astro import { transition } from 'astro:transitions'; --- <h1 transition:name="hero-title">About Us</h1> <img src="/about.jpg" alt="About Image" transition:name="hero-image" /> <a href="/" transition:name="cta-button">Back to Home</a>
Programmatic Navigation:
astro--- import { transition } from 'astro:transitions'; --- <button onClick={() => transition.navigate('/about')}> About Us </button> <a href="/contact" data-astro-transition="fade"> Contact Us </a>
Advanced Configuration:
astro--- // src/layouts/Layout.astro import { ViewTransitions } from 'astro:transitions'; --- <html> <head> <title>My Website</title> <ViewTransitions /> </head> <body> <script> import { navigate } from 'astro:transitions/client'; // Listen to navigation events document.addEventListener('astro:page-load', () => { console.log('Page loaded'); }); document.addEventListener('astro:after-preparation', () => { console.log('Page preparation complete'); }); // Custom navigation function customNavigate(url) { navigate(url, { history: 'push', state: { customData: 'value' }, }); } </script> <slot /> </body> </html>
Conditional Transitions:
astro--- // src/layouts/Layout.astro import { ViewTransitions } from 'astro:transitions'; --- <html> <head> <title>My Website</title> <ViewTransitions /> <script> // Apply transitions only to specific links document.querySelectorAll('a[href^="/blog/"]').forEach(link => { link.setAttribute('data-astro-transition', 'fade'); }); </script> </head> <body> <slot /> </body> </html>
Integration with Client Components:
jsx// src/components/Navigation.jsx import { useNavigate } from 'astro:transitions/client'; export function Navigation() { const navigate = useNavigate(); return ( <nav> <button onClick={() => navigate('/')}>Home</button> <button onClick={() => navigate('/about')}>About</button> <button onClick={() => navigate('/contact')}>Contact</button> </nav> ); }
Performance Optimization:
-
Prefetch Links:
astro<a href="/about" data-astro-transition-prefetch> About Us </a> -
Disable Transitions for Specific Pages:
astro--- // src/pages/no-transition.astro --- <script> // Disable view transitions document.documentElement.dataset.astroTransition = 'false'; </script> <h1>This page has no transition effects</h1> -
Optimize Image Loading:
astro--- import { Image } from 'astro:assets'; import heroImage from '../assets/hero.jpg'; --- <Image src={heroImage} alt="Hero" transition:name="hero-image" loading="eager" />
Event Listeners:
astro--- // src/layouts/Layout.astro import { ViewTransitions } from 'astro:transitions'; --- <html> <head> <title>My Website</title> <ViewTransitions /> </head> <body> <script> // Navigation starts document.addEventListener('astro:before-preparation', (ev) => { console.log('Preparing to navigate to:', ev.to.pathname); }); // Navigation preparation complete document.addEventListener('astro:after-preparation', () => { console.log('Navigation preparation complete'); }); // Page starts loading document.addEventListener('astro:before-swap', () => { console.log('Starting page swap'); }); // Page loaded document.addEventListener('astro:page-load', () => { console.log('Page loaded'); // Reinitialize client components initClientComponents(); }); // Navigation error document.addEventListener('astro:after-swap', (ev) => { if (ev.detail?.error) { console.error('Navigation error:', ev.detail.error); } }); </script> <slot /> </body> </html>
Best Practices:
- Add
<ViewTransitions />in layout components - Use
transition:namefor key elements to implement shared element transitions - Use
data-astro-transition-prefetchto prefetch important links - Listen to navigation events to handle client-side state
- Use different transition effects for different page types
- Consider user experience and don't overuse animations
- Simplify transitions on mobile devices
Compatibility:
View transitions require browser support for the View Transitions API. For unsupported browsers, Astro automatically falls back to normal page navigation.
Astro's view transitions provide SPA-like user experiences for static sites while maintaining the performance and SEO benefits of static sites.