Skip to main content
▲ Zone 5

View
Transitions

Seamless navigation. Native to the browser.

Click any card to see the transition →

← Observatory

The View Transitions API

For decades, navigating between pages felt like a light switch — binary, abrupt, contextless. The View Transitions API changes that. It gives the browser the power to visually connect two states of your interface, whether they're on the same page or two entirely different documents.

The mental model is simple: the browser takes a screenshot of the old state, then renders the new state. Between those two snapshots, you have full CSS control over how elements enter, exit, and morph. Named elements — those with a view-transition-name — get their own individual animation layer, and the browser interpolates their geometry automatically.

JavaScript

document.startViewTransition()

// Wrap any DOM mutation in a transition
document.startViewTransition(async () => {
  // This callback runs between the old and new state
  // Mutate the DOM here — update classes, innerHTML, etc.
  container.classList.toggle('expanded');
  await data.load();  // async is fully supported
});

// The transition object lets you hook into lifecycle
const transition = document.startViewTransition(updateDOM);
await transition.ready;   // animations are about to begin
await transition.finished; // all animations complete
CSS

view-transition-name

/* Give elements a unique identity across states */
.hero-image {
  view-transition-name: hero-img;
  /* Names must be unique in the document at any moment */
}

.product-card {
  /* Dynamic names via inline style or custom property */
  view-transition-name: product-42;
  contain: layout;  /* Required for named elements */
}

/* In JS, set dynamic names before the transition starts */
card.style.viewTransitionName = `card-$\{id}`;
CSS

::view-transition-old/new

/* The browser creates a pseudo-element tree for each named element */
::view-transition-old(hero-img) {
  /* The screenshot of the old state */
  animation: shrink-out 400ms ease-in-out both;
}

::view-transition-new(hero-img) {
  /* The live rendering of the new state */
  animation: expand-in 400ms ease-in-out both;
}

/* Apply different timings for different elements */
::view-transition-old(root),
::view-transition-new(root) {
  animation-duration: 300ms;
}
CSS

Cross-Document (zero JS)

/* Opt both pages into cross-document transitions */
@view-transition {
  navigation: auto;
}

/* Works for same-origin navigation — no JS needed at all. */
/* Add this to both the source and destination page's CSS. */

/* Match named elements on both pages for shared-element magic */
.product-hero {
  view-transition-name: product-hero;
}
/* The browser handles geometry interpolation automatically */
● Chrome 111+ ● Edge 111+ ● Safari 18+ ◐ Firefox (partial)

Same-document transitions have wide support. Cross-document transitions require @view-transition { navigation: auto } and Chrome/Edge 126+ or Safari 18.2+. Always feature-detect with if (document.startViewTransition).

Transition Configurator

Dial in your perfect transition. The generated CSS updates live.

State A
Click "Toggle" to transition →
0 transitions fired
Generated CSS