View Transitions API

A browser API that snapshots the old and new DOM, then animates between them, so navigation morphs with no animation library.

native page transitions without a libraryapp-like navigation in the browserstartViewTransitionview transition namebrowser built-in crossfade between pagescss page transitions no js libraryveiw transitions apismooth spa navigation natively

See it

Live demo coming soon

What it is

The browser screenshots the page before your DOM change, screenshots it after, and animates between the two for you. Same-document version: wrap the update in 'document.startViewTransition(() => updateDom())'. Cross-document version: add '@view-transition { navigation: auto; }' and same-origin page loads transition too, with no client-side router involved.

The default is a root crossfade, which you restyle with plain CSS animations on the '::view-transition-old(root)' and '::view-transition-new(root)' pseudo-elements. Tag any element with 'view-transition-name: hero-image' on both sides and it gets lifted out of the root snapshot and animated on its own, which is a shared element transition for roughly two lines of CSS.

Gotcha: every 'view-transition-name' must be unique in the document at snapshot time. Two elements with the same name (a list where you forgot to interpolate the id) skips the whole transition, silently. The snapshots are static images, so anything mid-animation freezes during the transition, and video keeps playing underneath but not in the snapshot. Support has been uneven across browsers, so feature detect 'document.startViewTransition' and fall back to an instant swap.

Ask AI for it

Add View Transitions to this app, picking the right mechanism per navigation type. For SPA route changes, wrap the router's DOM commit in 'document.startViewTransition(() => { ...dom update... })', feature detecting it first and falling back to an instant swap. For same-origin full-page navigation there is no callback to wrap, so opt in with '@view-transition { navigation: auto; }' in both documents instead. Style the default crossfade with CSS on '::view-transition-old(root)' and '::view-transition-new(root)' at 250ms ease-out, and give the article hero image a unique 'view-transition-name' on both the list and the detail page so it morphs between them. Make sure no two rendered elements share a name at snapshot time, and wrap the transition styles in a prefers-reduced-motion guard.

You might have meant

shared element transitionpage transitionlayout animationcrossfadecss animation

Go deeper