Web APIs, todayLab · Alex Harto

View Transitions

Animated transitions between states and between pages, with very little code.

In your browser: checking…Reviewed 1 Oct 2026

The browser captures the before and after and animates the difference. You decide which elements pair up (view-transition-name) and how they move, with CSS pseudo-elements. Within a page, wrap the change in document.startViewTransition().

Within a page they have been Baseline since October 2025 (Firefox 144). Across pages of the same site, @view-transition { navigation: auto; } is enough in Chrome, Edge and Safari; in Firefox it is still in development. This site uses it between entries.

What it is for

  • Lists that reorder or filter with continuity
  • From list to detail without losing your place
  • Multi-page sites that feel like an app

Demo

Every change runs inside document.startViewTransition(): the browser animates the difference. Click a swatch to open it. And across pages: go to the previous or next entry and watch the title.

Browser support

Baseline · newly available · 14 Oct 2025
FeatureDesktopMobile
ChromeEdgeFirefoxSafariChrome AndroidFirefox AndroidSafari iOS
Same document111Chrome: 111 111Edge: 111 144Firefox: 144 18Safari: 18 111Chrome: 111 144Firefox: 144 18Safari: 18
Across pages (@view-transition)126Chrome: 126 126Edge: 126 —1Firefox: No18.2Safari: 18.2 126Chrome: 126 —Firefox: No18.2Safari: 18.2
Element-scoped147Chrome: 147 147Edge: 147 —Firefox: No—Safari: No147Chrome: 147 —Firefox: No—Safari: No
  1. 1In development; part of Interop 2026.

Compatibility generated on every deploy from MDN browser-compat-data 8.1.3 (24 Sep 2026) · web-features 3.40.0 · checked by hand: 1 Oct 2026

Minimal code

<!doctype html>
<meta charset="utf-8">
<title>View Transitions · ejemplo mínimo</title>
<style>
  /* Entre páginas del mismo origen: basta con esta regla en las dos páginas */
  @view-transition { navigation: auto; }

  ul { display: flex; flex-wrap: wrap; gap: 8px; list-style: none; padding: 0; }
  li { width: 80px; height: 80px; display: grid; place-items: center; background: #c0643a; color: #fff; font: 600 24px system-ui; }
  /* Cada elemento anima por su cuenta; la clase permite darles a todos la misma curva */
  li { view-transition-name: match-element; view-transition-class: card; }
  ::view-transition-group(.card) { animation-duration: 0.4s; }
  @media (prefers-reduced-motion: reduce) {
    ::view-transition-group(*), ::view-transition-old(*), ::view-transition-new(*) { animation: none; }
  }
</style>
<p><button id="shuffle">Barajar</button> · <a href="pagina-2.html">Ir a la página 2 (transición entre documentos)</a></p>
<ul id="list"><li>1</li><li>2</li><li>3</li><li>4</li><li>5</li><li>6</li></ul>
<script>
  const list = document.querySelector('#list');
  const shuffle = () => [...list.children].sort(() => Math.random() - 0.5).forEach((li) => list.append(li));
  document.querySelector('#shuffle').onclick = () => {
    // Sin soporte, el cambio se hace igual, sin animación
    if (!document.startViewTransition) return shuffle();
    document.startViewTransition(shuffle);
  };
</script>

What’s new

  1. Chrome 147 brings element-scoped transitions (Element.startViewTransition).
  2. Interop 2026 includes cross-document transitions.
  3. Firefox 147 supports transition types.
  4. Firefox 144 ships them: Baseline within a page.

Keep in mind

  1. Across pages, both must opt in and be same-origin; a cross-origin redirect cancels it.
  2. match-element pairs by identity and only works within one document; across pages use unique names.
  3. Respect prefers-reduced-motion and check that startViewTransition exists before calling it.

Further reading

Sources