CSS View Transitions API
Native, framework-free animated transitions between two DOM states or two same-origin documents. The browser snapshots the old and new views, then cross-fades or morphs named elements between them. Replaces the JS-heavy FLIP and route-animation libraries for most cases.
Design Position
| Field | Value |
|---|---|
| Design family | CSS and platform primitives |
| Use when | Use when browser-native UI behavior depends on CSS View Transitions API. |
| System map | Design System Map |
| Proof path | Browser support, progressive enhancement, responsive behavior, and reduced-motion/accessibility checks where relevant. |
Two flavors
Same-document (SPA): document.startViewTransition(() => updateTheDOM()). The callback mutates the DOM, the browser animates old to new. Shipped in Chrome 111 (2023). Wrap in a capability check (if (!document.startViewTransition)) so unsupported browsers update instantly with no animation. Source: W3C CSS View Transitions Level 1, https://drafts.csswg.org/css-view-transitions/, 2026-05-31
Cross-document (MPA): opt in by adding @view-transition { navigation: auto; } to both the outgoing and incoming same-origin pages. No JavaScript and no meta tag required. Browsers without support fall back to a normal navigation, so it is pure progressive enhancement. Source: web.dev / trade-assistance 2026 guide, https://trade-assistance.com/blog/cross-document-view-transitions-mpa-2026/, 2026-05-31
How the animation is built
By default a transition is a full-page crossfade. To morph a specific element, give it view-transition-name: hero (the name must be unique per page). The browser then animates that element's position, size, and content independently of the page fade.
Customize each part with the generated pseudo-elements: ::view-transition-old(name), ::view-transition-new(name), and the wrapping ::view-transition-group(name). Target them with normal @keyframes and CSS animations. Source: MDN View Transitions API, https://developer.mozilla.org/en-US/docs/Web/API/View_Transition_API, 2026-05-31
Cross-document lifecycle hooks
For MPA transitions, set names and transition types just-in-time with two events:
pageswapfires on the old page before it unloads. Readevent.viewTransition, optionallyskipTransition()for back/forward (traverse) navigations.pagerevealfires on the new page before first paint. Add types withevent.viewTransition.types.add('coming-from-list')to switch keyframes per route. Source: W3C CSS View Transitions Level 2, https://drafts.csswg.org/css-view-transitions-2/, 2026-05-31
Pair with the Speculation Rules API (prefetch / prerender) so the next document is ready before the user clicks, which makes the transition feel as instant as a native app.
Browser support (2026-05-31)
| Feature | Chrome / Edge | Safari | Firefox |
|---|---|---|---|
| Same-document | 111+ | 18.0+ | partial |
| Cross-document | 126+ | 18.2+ | flag / Nightly partial |
Cross-document support sits near 85% of tracked usage. Firefox exposes both behind flags only, so treat MPA transitions as enhancement, never a hard dependency. Source: caniuse cross-document view transitions, https://caniuse.com/cross-document-view-transitions, 2026-05-31
Design-engineering guidance
- Use it for thumbnail to hero morphs (list to detail), tab and filter changes, and full marketing or docs page navigations where it is free polish.
- Keep one or two named morphs per transition. Naming everything produces noise and breaks the snapshot when names collide.
- Always gate decorative motion with
@media (prefers-reduced-motion: reduce); skip or shorten the transition. See Motion 3D Playbook for timing defaults. - In React, the experimental
<ViewTransition>component andstartTransitionintegrate with this API; see Frontier Stack 2026 for stack placement. For Sigil and Dedalus surfaces, prefer the native API over a route-animation library. - Plumbing (
@view-transition, global keyframes) belongs inglobals.cssper CSS UI Enforcement; components staycn()-first.
Timeline
- 2026-07-01 | Design category refresh added this page to the CSS and platform primitives family, linked it to Design System Map, and kept it standalone because CSS View Transitions API owns a distinct design decision surface in this family. Source: User request, 2026-07-01
- 2026-05-31 | Page created. Captured the same-document vs cross-document split, the
@view-transitionopt-in,view-transition-namemorphing, the::view-transition-*pseudo-elements,pageswap/pagerevealhooks, Speculation Rules pairing, and the Chrome 126+ / Safari 18.2+ / Firefox-flag support matrix. Source: caniuse + W3C View Transitions L1/L2 + MDN + web.dev, 2026-05-31