DEV Community

linou518
linou518

Posted on

View Transitions API: Native Browser Page Transitions, No More Framer Motion

Have you ever installed all of Framer Motion into a React app just to get a page transition fade-in?

Or hand-written a pile of requestAnimationFrame logic for a multi-page site, managing your own snapshots and compositing, only to end up with something less natural than a native app?

In October 2025, the platform gave us the official answer.

View Transitions API officially joined Baseline Newly Available — same-document transitions are fully supported across Chrome 111+, Edge 111+, Firefox 133+, and Safari 18+. The browser natively handles snapshots, compositing, and animation. You just tell it "the DOM is about to change."


How It Works: Three-Phase Snapshot, Browser Handles Everything

View Transitions API has an elegant design. It breaks a transition into three phases:

  1. Snapshot old state — the browser takes a screenshot of the current page
  2. Execute DOM update — your callback runs, the DOM changes
  3. Snapshot new state → calculate diff → generate animation — the browser auto-interpolates

All of this happens within a single frame. Users never see a jarring switch — only a smooth transition.

The key insight: the browser handles snapshots and compositing; you only need to think about logic.


Minimum Implementation: One Line of Code

SPA (Single Page Application)

// Before
updateTheDOMSomehow();

// After
document.startViewTransition(() => updateTheDOMSomehow());
Enter fullscreen mode Exit fullscreen mode

That's it. The default effect is a cross-fade. No CSS required.

MPA (Multi-Page Application)

/* Two lines of CSS for your entire site's page navigation */
@view-transition {
  navigation: auto;
}
Enter fullscreen mode Exit fullscreen mode

Add this to your global CSS and every <a> link navigation automatically gets a transition animation. Exceptionally high ROI.


Custom Animations: CSS Pseudo-Elements

Not happy with the default fade? During a transition, the browser exposes two CSS pseudo-elements:

/* Old state snapshot — slide out left */
::view-transition-old(root) {
  animation: slide-out-left 0.3s ease-out;
}

/* New state — slide in from right */
::view-transition-new(root) {
  animation: slide-in-right 0.3s ease-out;
}

@keyframes slide-out-left {
  to { transform: translateX(-100%); }
}

@keyframes slide-in-right {
  from { transform: translateX(100%); }
}
Enter fullscreen mode Exit fullscreen mode

Control duration, easing, and animation effect through CSS — same as any regular CSS animation.


Named Transitions: Element-Level Morph Animation

This is View Transitions' most powerful capability — automatically morphing between same-named elements in different states.

Want "click a list thumbnail and it smoothly expands into the full detail image"?

/* List page thumbnail */
.thumbnail {
  view-transition-name: product-image;
}

/* Detail page full-screen image */
.fullscreen-image {
  view-transition-name: product-image;
}
Enter fullscreen mode Exit fullscreen mode

The browser automatically calculates position and size differences between the two elements across pages/states, then generates interpolated animation. No manual coordinate calculation, no absolute positioning tricks.

Great for:

  • List → detail page navigation (iOS-style card expansion)
  • Image gallery fullscreen expand
  • Shopping cart fly-in animation
  • Data table row expansion

Comparison With Existing Solutions

Solution Bundle Size Framework Dependency MPA Support Browser Support
Framer Motion ~50KB React All
React Spring ~25KB React All
GSAP ~70KB None Manual All
View Transitions API 0KB None Chrome/Edge/Safari/Firefox(SPA)

Zero dependencies, zero bundle, native MPA support. For new projects with modest animation needs, View Transitions is the default choice.


Promise API: Precise Timing Control

const transition = document.startViewTransition(() => updateDOM());

// Wait for animation to start (pseudo-elements created, animation about to begin)
await transition.ready;
// Use Web Animations API here for further control

// Wait for animation to finish
await transition.finished;
// Do cleanup or next actions here
Enter fullscreen mode Exit fullscreen mode

Useful for: chained animation orchestration, firing analytics events when animation completes, updating router state after transition.


Gotchas to Avoid

1. Snapshots are bitmaps, not live DOM

During animation, elements become screenshots (images). font-size animations and clip-path changes don't take effect during the animation. If you need font size transitions, trigger them after the animation ends.

2. Named elements must be unique on the page

Each view-transition-name can only be used by one element per page. List item Morph animations require dynamic name assignment (view-transition-name: item-${id}), set via JS on click:

item.style.viewTransitionName = `item-${item.dataset.id}`;
document.startViewTransition(() => navigateToDetail());
Enter fullscreen mode Exit fullscreen mode

3. Cross-page morph requires consistent aspect ratios

If same-named elements have different aspect ratios across pages, the morph animation will warp. Text content is especially prone to line-wrapping issues — design with both endpoints' content dimensions in mind.

4. Firefox MPA support isn't there yet

Cross-document navigation (MPA page transitions) with View Transitions isn't supported in Firefox yet (expected in 2026). For Firefox-required MPA scenarios, use progressive enhancement with @supports:

@supports (view-transition-name: none) {
  @view-transition {
    navigation: auto;
  }
}
Enter fullscreen mode Exit fullscreen mode

5. Watch your INP metrics

If transition animations occupy the main thread too long, they'll affect INP (Interaction to Next Paint). Keep animations simple; avoid complex synchronous operations inside the startViewTransition callback.


Graceful Degradation: Non-Supporting Browsers Unaffected

View Transitions' most developer-friendly characteristic: in non-supporting browsers, the DOM updates normally — it just has no animation.

function showView(name) {
  if (document.startViewTransition) {
    document.startViewTransition(() => _doShowView(name));
  } else {
    _doShowView(name);  // fallback: direct switch, no animation
  }
}
Enter fullscreen mode Exit fullscreen mode

Zero breakage, progressive enhancement, existing users unaffected.


Conclusion

View Transitions API is mature enough to be the default choice for new projects.

For SPAs, one startViewTransition call replaces mountains of Framer Motion boilerplate. For MPAs, two lines of CSS add transition effects to your entire site's navigation. For iOS-level card expansion, view-transition-name morph covers the use case.

Zero bundle size, no framework dependency, zero degradation risk. This API is underrated.


Sources: Trevor Lasn's View Transitions API Guide; Cyd Stumpel's Practical CSS View Transitions Guide; MDN Web Docs Baseline 2025

Top comments (0)