Skip to content
Carl Victor Fontanos
Carl Victor Fontanos

Carl Victor Fontanos

Software Engineer

I build web applications and share what I learn along the way.

© 2026

View Transitions: The Crossfade Between States Is Now One Call

C
Carlo Fontanos
· 2 min read

The hardest animations to hand-build are transitions between layouts: a card grid re-sorting, an item deleted and the rest closing ranks, light mode to dark. FLIP technique, position math, clone elements... or:

document.startViewTransition(() => {
    renderSortedGrid();    // any DOM mutation - your normal render code
});

The browser snapshots the old state, runs your callback, snapshots the new state, and crossfades between them. Your rendering logic doesn't change at all - the transition wraps it. That's the entire basic API.

Naming elements makes them travel

The default is a full-page crossfade. Give elements a view-transition-name and they animate independently - position, size and all:

.card.selected { view-transition-name: active-card; }

/* Customize any piece - these are real pseudo-elements */
::view-transition-old(active-card) { animation-duration: 0.3s; }
::view-transition-group(active-card) { animation-timing-function: cubic-bezier(0.2, 0, 0.2, 1); }

A thumbnail that grows into a detail view, a row that glides to its new sorted position - the browser matches old and new elements by name and animates the difference. Names must be unique per snapshot, so for lists, assign them dynamically (el.style.viewTransitionName = 'item-' + id) or scope them to the elements that move.

Progressive enhancement is built into the shape

function withTransition(update) {
    if (!document.startViewTransition) return update();     // just do it, unanimated
    return document.startViewTransition(update);
}

Because the callback is your normal update, unsupported browsers simply update instantly - no broken states, no forked logic. Support: Chromium 111+, Safari 18+, Firefox landing it now - which is exactly the profile where enhancement-not-requirement is the right posture. Wrap it once, use it everywhere.

Field notes

  • The callback can return a promise (async renders welcome); the page freezes interaction briefly during the capture, so keep updates snappy.
  • Respect prefers-reduced-motion - skip startViewTransition entirely when reduce is set.
  • Theme toggles are the gateway drug: wrap your dark-mode switch and the whole page crossfades instead of flashing. Ten seconds of work, disproportionate polish.
  • Same-document transitions are this API; cross-page transitions for MPAs exist behind @view-transition CSS in Chromium and are worth watching - your PHP site may get SPA-feeling navigation without the SPA.

For per-element, data-driven motion, element.animate() is still the tool. View transitions own the layer above: whole states, whole layouts, one function call.

C
Written by Carlo Fontanos

Full-stack web developer sharing practical tutorials and building tools that ship.

Got something on your mind?

My inbox is open - no forms disappearing into the void here.

  • Just say hello Found a tutorial useful? Spotted a mistake? Tell me.
  • Hire me for a project Have something custom in mind? Let's talk scope and timelines.
  • Product support Bought something here? I'll help you get it running.

I usually reply within 1-2 business days.

Message sent!

Your details are only used to reply to you.

Keep reading