Topic: Web platform

View Transitions Make MPAs Smoother, Not SPAs

The View Transition API now covers same-document state changes and page navigation. Here is the minimal approach to fallbacks, shared elements, and reduced motion.

Animated meme (expand/collapse)
You wanted a cross-fade and somehow built an entire SPA machine first. · Source: GIPHY

Making a thumbnail flow smoothly from an article list into the detail-page hero used to have a familiar prerequisite: turn the site into an SPA, then add router transitions, state management, and JavaScript that knows when the animation is finally over.

Today, a cross-page effect can begin with two lines of CSS:

@view-transition {
  navigation: auto;
}

It is easy to see why recent View Transition recipes on daily.dev and a Reddit discussion of useful modern Web APIs attracted attention. The API has moved beyond interesting demos into ordinary product territory.

One misconception should go first: View Transitions handle the visual handoff between states. They do not provide routing, data fetching, caching, optimistic updates, or offline state. They can make an MPA feel more continuous, but they do not turn it into an SPA.

That is the advantage. If a site does not need a client router, it no longer needs to adopt one merely to animate navigation.

Two kinds of transition, one underlying idea

MDN’s View Transition API guide covers two paths:

Situation Trigger Good fit
Same-document document.startViewTransition(update) Sorting, pagination, calendar changes, SPA routes
Cross-document @view-transition { navigation: auto; } Navigation inside a same-origin MPA

A same-document transition captures the old state, runs the callback that updates the DOM, then animates the old view out and the new view in. After Firefox 144 shipped the core features, this became Baseline Newly available in October 2025.

A cross-document transition needs no JavaScript. The browser handles snapshots and navigation between the old and new documents, with three important conditions:

  1. Both pages must be same-origin.
  2. Both source and destination must opt in with @view-transition.
  3. The navigation must not pass through a cross-origin redirect.

Those conditions come from the cross-document model in CSS View Transitions Level 2. Authentication services, third-party payments, and external links commonly fall outside it; leave them as normal navigations.

The safest MPA starting point: opt in only when motion is welcome

MDN still marks @view-transition as Limited availability. Fortunately, this is an unusually clean progressive enhancement. An unsupported browser ignores the rule, follows the link, and loads the new page normally.

I would start with the more conservative version:

@media (prefers-reduced-motion: no-preference) {
  @view-transition {
    navigation: auto;
  }
}

There is no animation library, feature-detection script, or fallback router. Supporting browsers whose users have not requested reduced motion receive the default cross-fade. Everyone else keeps the site’s already reliable navigation.

The failure mode remains safe. In Chrome, if the destination takes more than roughly four seconds, the browser skips the transition rather than leaving a snapshot over the page indefinitely. The transition is an enhancement, never an entrance requirement.

Shared elements are about identity, not animation

A whole-page cross-fade needs only the opt-in. To move a list thumbnail into an article hero, the elements on each side share a view-transition-name:

/* Exactly one matching element on each page */
[data-transition-cover="42"] {
  view-transition-name: cover-42;
}

The thumbnail for article 42 and the detail-page hero both use cover-42, allowing the browser to pair their old and new snapshots. The name means “these represent the same visual object,” not “apply this animation preset.”

Two traps matter here:

  • A visible page cannot contain two elements with the same name. Giving every card in a list view-transition-name: cover does not let the browser guess which one was clicked.
  • view-transition-name: match-element can automatically name many elements in a same-document transition, but DOM nodes in separate documents do not share identity. It cannot create a cross-page shared element.

The requirement is therefore a stable ID, not an animation helper. Let the template generate cover-<id> from an article slug or data ID. No animation registry is necessary.

An SPA should keep its update logic independent

The lowest-risk same-document approach keeps one update function that works without animation:

function updateResults() {
  results.replaceChildren(...nextItems);
}

if (document.startViewTransition) {
  document.startViewTransition(updateResults);
} else {
  updateResults();
}

The callback does not hand application state to View Transitions. It tells the browser: “the old state is ready to capture; now run the real DOM update.”

Keep that boundary. Finish data loading first and preserve the existing error path. The data and DOM update must still succeed if animation is unavailable or abandoned. Putting fetches, router side effects, and animation timing into the callback quickly turns a visual enhancement into a new control center.

What it cannot replace in a router

View Transitions make server-rendered navigation feel more coherent, but the following remain architecture problems, not animation problems:

  • A persistent application shell
  • Complex client state that survives navigation
  • Optimistic or offline interaction
  • Partial updates instead of complete-document responses
  • Route loaders, prefetching, and caches that are central to product performance

When those are requirements, a client router may still be correct. When they are absent and the page change merely feels abrupt, try the platform’s cross-document transition first.

My selection rule is straightforward:

Requirement Approach
Move between calendar months or reorder a list Same-document transition
Open an article from an article list Cross-document transition
Authentication, payment, external site Normal navigation
Optimistic dashboard or offline app Router/SPA architecture
Button hover or a single expanding panel Ordinary CSS transition

The last row matters. Not every movement needs snapshots and a pseudo-element tree. When the element still exists in place, CSS transition is usually more direct.

Animated meme (expand/collapse)
If a cross-fade starts demanding a router, global store, and lifecycle manager: that is not necessary. · Source: GIPHY

Animation should explain direction, not prove that it exists

The default View Transition is a cross-fade, which is already safer than making every page fly in from the right. Custom animation earns its place when it explains space or causality:

  • A selected thumbnail becomes the detail-page hero.
  • A calendar moves left for the next month and right for the previous one.
  • Sorted items travel to their new positions instead of disappearing and reappearing.

Whole-page rotations, scaling, and 3D flips make good demos but poor interfaces for repeated work. Every extra millisecond of spectacle spends the user’s attention.

Do not interpret prefers-reduced-motion as “play the same animation faster.” MDN’s reduced-motion guidance replaces potentially triggering scale motion with a gentler effect. The simplest product default is to enable cross-page transitions only under no-preference. If a reduced mode remains animated, use a short dissolve rather than large translation or scaling.

Five checks before shipping

  1. Disable support and test again. Every action must still complete.
  2. Enable the operating system’s Reduce Motion setting. Large slides and scaling must disappear.
  3. Test Back and Forward. Temporary transition names must not conflict after BFCache restores a page.
  4. Test slow pages and error responses. Animation must not hide an error or block navigation.
  5. Test responsive breakpoints. A name must resolve to only one visible element at every width.

Discuss easing and duration after these checks pass. The best fallback for View Transitions is not another animation system; it is a website that already works.

Conclusion: treat transitions as CSS, not architecture

The important development in the View Transition API is not the number of elaborate effects it can produce. It is that a normal website no longer has to become an SPA to provide visual continuity between pages.

Core same-document support now spans the major engines. Cross-document support is not fully Baseline, yet it falls back quietly to ordinary navigation. That makes it a good progressive enhancement today.

My default is simple: make navigation and DOM updates completely correct with zero animation, then add View Transitions only where motion explains position, direction, or cause.

If a transition starts demanding a custom router, global animation store, or lifecycle manager, the likely problem is not a weak API. A visual enhancement has escaped into architecture.


External references