View Transitions API Performance

This guide is part of Animation & Compositing Performance, within Rendering & CSS Performance. The View Transitions API animates between two states of a page — or between two pages — with a few lines of code. For same-document transitions, document.startViewTransition(callback) captures a snapshot of the current state, runs your callback to update the DOM, captures the new state, and animates between them with CSS. For cross-document transitions, the @view-transition { navigation: auto; } rule enables the same effect across same-origin navigations in supporting browsers.

The API is efficient in that the animation itself runs on snapshots, typically on the compositor. But the transition has costs around it: capturing snapshots requires rendering, the page is non-interactive while the transition runs, many named elements multiply snapshot work and memory, and cross-document transitions can delay the moment the new page is shown. Used carelessly, view transitions can make INP and perceived navigation speed worse.

Same-document view transition lifecycle Stages of a same-document view transition from capturing the old state to finishing the animation. Same-document view transition lifecycle Capture old snapshot named elements Callback update DOM Capture new render + snapshot Animate pseudo-elements, compositor Finish live DOM shown

Rapid Diagnosis

  • Record a trace of the interaction that triggers the transition; note time from input to first animated frame.
  • Count elements with view-transition-name at the time of the transition.
  • Check the update callback: does it fetch data or do heavy work before resolving?
  • Measure transition durations; long animations keep the page non-interactive.

Root Cause Analysis

1. Slow update callbacks. The new state cannot be captured until the callback resolves, delaying the first frame after input.

2. Many named elements. Each named element is captured and animated separately, increasing rendering and memory cost.

3. Long animations. Pointer events go to the transition overlay, not the page, while the transition runs.

4. Large snapshots. Full-page or very tall named elements produce large textures.

Step-by-Step Resolution

1. Keep the DOM update fast

javascript
async function showProduct(id) {
  const data = await fetchProduct(id);                 // fetch BEFORE starting the transition
  if (!document.startViewTransition) { render(data); return; }
  document.startViewTransition(() => render(data));    // synchronous, fast update
}
// trade-off: fetching first delays the start of the transition, but the transition
// itself is short and the page stays interactive while data loads.

2. Limit named elements

Name only the elements that need to morph (a thumbnail becoming a hero, a title moving). Let the rest of the page cross-fade as the root snapshot. Avoid naming every list item; if you must, name only items visible in the viewport.

3. Keep transitions short

Use 150–300ms for UI transitions. Set durations on ::view-transition-group(*) and specific groups.

css
::view-transition-group(*) { animation-duration: 220ms; }
@media (prefers-reduced-motion: reduce) { ::view-transition-group(*) { animation: none; } }
/* trade-off: shorter transitions look snappier and return interactivity sooner,
   but very short ones can feel abrupt for large layout changes. */

4. For cross-document transitions, avoid blocking rendering

Cross-document transitions wait for the new page to be ready to render. Keep the new page's critical path fast (critical CSS, no render-blocking scripts), and avoid using <link rel="expect" blocking="render"> on elements far down the page, which delays the first frame.

Interaction to first transition frame Bar chart comparing time from tap to the first animated frame when the view transition callback fetches data versus when data is fetched first. Interaction to first transition frame Fetch inside callback (page frozen) 620ms Fetch first then transition 40ms In the second case the fetch still takes ~560ms, but the page stays interactive.

Verification

Record the interaction: the time from input to the first transition frame should be short (under 100ms) and no long task should precede it. Count named elements during the transition in DevTools (the Elements panel shows ::view-transition pseudo-elements). Check INP for the triggering interaction in the field, and for cross-document transitions, compare LCP and FCP of navigations with and without the transition.

A photo gallery app used a view transition to morph thumbnails into a full-size viewer. The callback awaited image data and decoding inside startViewTransition, and every thumbnail on the page had a view-transition-name. Opening a photo froze the page for 400–700ms before animating, and INP for thumbnail taps was 620ms. The team fetched and decoded the image (img.decode()) before starting the transition, and assigned a view-transition-name only to the tapped thumbnail and the viewer image, just before the transition. Time to the first animated frame fell to 45ms, and INP p75 for thumbnail taps to 140ms.

Should this change use a view transition? Decision sequence for whether a UI change benefits from a view transition and how to set it up. Should this change use a view transition? Does the update need data or async work? Fetch first, then start the transition yes no Do more than a few elements need to morph? Name only those in view; cross-fade the rest yes no Is it a frequent action (typing, filtering)? Skip the transition yes no Use a short transition (150-300ms) with reduced-motion support

Cross-Document Transitions and Navigation Speed

Cross-document view transitions make multi-page sites feel like apps, but they couple the old and new page. The old page's snapshot is held until the new page renders its first frame, then the transition animates. If the new page is slow to render, users see the old page frozen rather than a blank screen — arguably better, but the delay is the same. If the transition adds render-blocking requirements (waiting for specific elements), it can delay first paint. Measure navigation timings with and without the transition; combine with speculation rules (prerendering) to make the new page ready instantly, which is where cross-document transitions look and perform best.

Measuring Transition Cost

To see what a transition costs, record two traces of the same interaction — one with startViewTransition and one with the update applied directly. Compare the time from input to the next frame, the rendering work during capture, and the overall time until the page accepts input again. In the field, tag interactions that triggered a transition in your INP reporting, so you can compare INP for transitioned and non-transitioned updates. If transitions add more than a few tens of milliseconds before the first frame, reduce named elements or simplify the update.

Common Mistakes

  • Doing async work inside the callback. The page freezes while it waits.
  • Naming every element. Snapshot cost and memory grow with each named element.
  • Long, elaborate animations. The page is non-interactive for their duration.
  • Animating the LCP element on navigation. May delay when it is considered painted.

Edge Cases

Duplicate names. Two elements with the same view-transition-name abort the transition; ensure uniqueness at capture time.

Scroll position changes. The root snapshot covers the viewport; transitions involving large scroll changes may look odd and need custom handling.

Third-party content. Iframes are captured as images; their contents do not animate.

Low-memory devices. Many large snapshots can be expensive; keep named elements small.

FAQ

Do view transitions run on the compositor?

The animation of snapshot pseudo-elements typically uses transforms and opacity and can run on the compositor. Capturing snapshots and updating the DOM happen on the main thread.

Can the user interact during a view transition?

No. During the transition, the page is covered by the transition pseudo-elements, so input does not reach the page until it finishes.

Do view transitions affect INP?

They can. If the update callback is slow, the next paint after the interaction is delayed. A fast callback and short transition keep INP low.

Do cross-document transitions slow down navigation?

They add little overhead if the new page renders quickly. They do not make the new page load faster; combine them with prerendering for instant-feeling navigations.

How many named elements are reasonable?

A handful per transition. Each adds snapshot and animation work; name only what needs to morph.

Can I skip a transition?

Yes. Call transition.skipTransition() to jump to the end state, useful when a new navigation starts before the previous transition finishes.

Do view transitions work with frameworks?

Yes. Frameworks wrap state updates in startViewTransition, and several routers provide built-in integration. Keep the wrapped update synchronous and fast.

Should I use view transitions for every route change?

Not necessarily. They suit navigations where continuity helps users understand what changed, like opening an item from a list. For frequent or unrelated navigations, an instant change is often better.