One of the things native mobile apps have always had over the web is smooth transitions between screens. Navigating in a browser traditionally means an instant swap — old content gone, new content appears. The View Transitions API changes this with a browser-native mechanism for animating between states, and it's now in all major browsers.
How It Works ​
The API works by capturing a screenshot of the current state, applying the new state, then cross-fading between the two using CSS animations you control. The core is a single method:
document.startViewTransition(() => {
// Any DOM mutation here will be animated
updatePageContent();
});
Without any extra CSS, you get a smooth cross-fade for free. That alone is a significant upgrade for most SPAs. But the real power comes when you name elements to create matched transitions.
Named Elements and Matched Transitions ​
When you give an element a view-transition-name, the browser tracks that element across the transition and animates it from its old position and size to its new one:
/* Mark the element you want to animate across views */
.hero-image {
view-transition-name: hero-image;
}
.product-thumbnail {
view-transition-name: product-thumb;
}
document.startViewTransition(() => {
// Swap the list view for the detail view
container.innerHTML = renderDetailView(product);
});
If both views have an element with view-transition-name: hero-image, the browser morphs the element between its two positions — like a shared element transition in native apps. The animation is driven by CSS, so you have full control:
/* Target the animated snapshot pairs */
::view-transition-old(hero-image) {
animation: fade-out 0.3s ease;
}
::view-transition-new(hero-image) {
animation: fade-in 0.3s ease;
}
/* Or let the browser interpolate position/size automatically */
::view-transition-group(hero-image) {
animation-duration: 0.4s;
animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);
}
Multi-Page Applications with Navigation API ​
The initial release of View Transitions only covered same-document transitions. Cross-document (MPA) support has now landed in Chrome and is coming to other browsers. You opt in with a single meta tag:
<meta name="view-transition" content="same-origin" />
With this in place, navigating between pages on the same origin automatically triggers a cross-fade. Add view-transition-name to persistent elements (nav, header, a hero image that exists on multiple pages) and you get native-feeling page transitions with zero JavaScript.
Practical Tips ​
A few patterns that make the API easier to work with in real projects:
// Graceful degradation — not all browsers support this yet
if (!document.startViewTransition) {
updatePageContent();
return;
}
const transition = document.startViewTransition(() => {
updatePageContent();
});
// Wait for the animation to finish before doing cleanup
await transition.finished;
cleanup();
Keep view-transition-name values unique per page — duplicate names cause the browser to skip the matched animation for those elements. For list items, you can set the name dynamically:
items.forEach((item) => {
item.element.style.viewTransitionName = `item-${item.id}`;
});
View Transitions won't replace dedicated animation libraries for complex choreography, but for the common case of animating between routes and promoting individual elements across page changes, it's the right tool — fast, native, and CSS-controllable.

