View Transitions API Cheat Sheet
Syntax for document.startViewTransition, CSS pseudo-elements for customizing the crossfade, and the multi-page transition spec.
SPA View Transition
Wrap a DOM update in startViewTransition to get an automatic crossfade animation.
function updateContent(newHtml) { if (!document.startViewTransition) { document.getElementById('app').innerHTML = newHtml return } document.startViewTransition(() => { document.getElementById('app').innerHTML = newHtml })}
Naming Elements for Shared-Element Transitions
Tag elements with view-transition-name so the browser morphs between their old/new states.
.product-hero-image { view-transition-name: hero-image;}/* the browser automatically finds an element with the same view-transition-name in the "after" DOM state and animates a smooth morph between the two positions/sizes */
Customizing the Transition Animation
Override the default crossfade with your own keyframes via the ::view-transition pseudo-elements.
::view-transition-old(hero-image),::view-transition-new(hero-image) { animation-duration: 0.4s; animation-timing-function: cubic-bezier(0.4, 0, 0.2, 1);}::view-transition-old(root) { animation: fade-out 0.3s ease-out;}::view-transition-new(root) { animation: fade-in 0.3s ease-in;}@keyframes fade-out { to { opacity: 0; } }@keyframes fade-in { from { opacity: 0; } }
Cross-Document (MPA) Transitions
Opt full page navigations into transitions with a single CSS declaration on both pages.
/* add to both the source and destination page's CSS */@view-transition { navigation: auto;}
View Transitions API Reference
Core objects and pseudo-elements.
- document.startViewTransition(callback)- captures before/after screenshots and runs the DOM-mutating callback
- ViewTransition.ready- promise resolves once pseudo-element tree is built, before animation starts
- ViewTransition.finished- promise resolves when the transition animation completes
- ViewTransition.skipTransition()- cancels the animation, applying the new DOM state instantly
- view-transition-name- CSS property linking an element across old/new snapshots for shared-element morphing
- ::view-transition-group/-image-pair/-old/-new- pseudo-element tree you can target for custom animation
Conditional Styling with Transition Types
Tag a transition with named types so CSS can branch the animation (e.g. forward vs. back navigation) without extra JS state.
document.startViewTransition({ update: () => renderNextPage(), types: ['forward'],})/* in CSS: *//*:root:active-view-transition-type(forward) { &::view-transition-old(root) { animation: slide-out-left 0.3s both; } &::view-transition-new(root) { animation: slide-in-right 0.3s both; }}*/
pageswap / pagereveal for Cross-Document Transitions
Hook into the exact moments a same-origin navigation leaves and enters, to customize an MPA transition from JS.
window.addEventListener('pageswap', (e) => { if (e.viewTransition) { e.viewTransition.types.add('leaving') }})window.addEventListener('pagereveal', (e) => { if (e.viewTransition) { e.viewTransition.ready.then(() => console.log('new page ready to animate in')) }})
Respecting prefers-reduced-motion
Disable or shorten the animation for users who've opted out, while still applying the DOM/state update.
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none !important; }}/* JS alternative: gate startViewTransition entirely *//* if (matchMedia('(prefers-reduced-motion: reduce)').matches) { plainUpdate() } else { document.startViewTransition(plainUpdate) } */
Async Update Callbacks
The update callback may return a promise; the browser waits for it (and for fonts/images to be ready) before capturing the new state.
const transition = document.startViewTransition(async () => { const data = await fetch('/api/page-data').then((r) => r.json()) renderPage(data) await document.fonts.ready})transition.ready.then(() => console.log('pseudo-element tree built'))transition.finished.then(() => console.log('transition fully done'))
Advanced View Transitions Reference
Newer API surface for typed, cross-document, and JS-driven transitions.
- types (option / ViewTransition.types)- a live Set of string tags used with :active-view-transition-type() to branch CSS per navigation kind
- pageswap event- fires on the outgoing document just before a cross-document navigation's transition starts capturing
- pagereveal event- fires on the incoming document as it's about to be revealed, before the new-state snapshot is taken
- PageSwapEvent.viewTransition / PageRevealEvent.viewTransition- the ViewTransition object for a cross-document transition, or null if none is active
- :active-view-transition / :active-view-transition-type()- CSS pseudo-classes matching the document (or a specific type) while a transition is in flight
- view-transition-class- assigns a shared class to the generated pseudo-elements for several view-transition-names, so you can style a group without repeating selectors
Always feature-detect with `if (!document.startViewTransition)` and fall back to the plain DOM update — Safari and Firefox support lag Chrome, and an ungated call will throw in older engines.