CSS View Transitions API: Native App-Like Page Transitions
How to build seamless morphing page transitions. Master document.startViewTransition(), view-transition-name, and cross-document multi-page transitions.

Historically, creating fluid, animated page transitions (such as morphing a thumbnail card into a full-screen hero image during navigation) required complex JavaScript animation libraries, router interception, and heavy virtual DOM diffing.
The CSS View Transitions API brings native, browser-accelerated page morphing and state transition animations to the web platform with just a few lines of code.
1. Single Page App (SPA) View Transitions
In client-side applications (React, Vue, vanilla JS), wrap your DOM update inside document.startViewTransition():
function updatePageContent(newHTML) {
// Fallback for browsers without View Transitions
if (!document.startViewTransition) {
document.getElementById('content').innerHTML = newHTML;
return;
}
// 1. Browser takes snapshot of Old State (::view-transition-old)
// 2. Callback runs and mutates DOM
// 3. Browser takes snapshot of New State (::view-transition-new)
// 4. Automatically cross-fades and morphs between states!
document.startViewTransition(() => {
document.getElementById('content').innerHTML = newHTML;
});
}
2. Element Morphing with view-transition-name
To connect a specific element across two different pages (e.g. morphing a small product thumbnail on /catalog into the main hero image on /product/123), give both elements the same view-transition-name:
/* On the catalog card */
.product-card-thumbnail {
view-transition-name: product-hero-image;
}
/* On the destination product detail page */
.product-hero-image {
view-transition-name: product-hero-image;
}
Catalog Page: [Thumbnail] ──(Click)──> [View Transition] ──> Detail Page: [Hero Image]
│ │
└────── Browser automatically animates position ─────┘
and scale between the two elements! ✅
3. Multi-Page Application (MPA) Transitions
Modern browsers also support View Transitions across standard multi-page navigations (e.g. Astro, server-rendered sites) without client-side routing!
Simply declare in your CSS:
@view-transition {
navigation: auto;
}
4. Customizing Animations with Pseudo-Elements
Style the transition animation using native pseudo-elements:
::view-transition-old(root) {
animation: 0.3s ease-out both fade-out;
}
::view-transition-new(root) {
animation: 0.3s ease-in both fade-in;
}
/* Respect user motion preferences */
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation: none !important;
}
}
Next Steps
- Continue to the next guide: CSS Scroll-Driven Animations.
