Skip to main content

Command Palette

Search for a command to run...

View Transitions — Rethinking How UI Changes Are Animated

This Is Not Just Another Animation API

Published
5 min read
View Transitions — Rethinking How UI Changes Are Animated

We’ve had animations on the web for a long time.

CSS transitions
CSS animations
JS-based animation libraries

They all try to solve the same problem:

Move UI from one state → to another state.

But they all share the same limitation:

They animate elements.

Not views.


First, What Is a “Transition”?

Before jumping into APIs, lets look into transition.

A transition is not:

“fade this div”

A transition is:

“move the user from one UI state to another, without breaking continuity”

Example:

  • Clicking a product → opens product page

  • Switching tabs → content changes

  • Filtering a list → items reorder

Without transitions:

UI jumps

With transitions:

UI flows


The Core Problem With Traditional Animations

Let’s take a simple route change.

You go from:

Home → Product Page

What happens?

  • Old DOM is removed

  • New DOM is inserted

There is no connection between them

So developers try to fake it:

  • clone elements

  • manually position

  • animate opacity/position

  • sync timings

This becomes:

complex
fragile
hard to maintain

This is why most apps either:

  • don’t animate route changes

  • or use heavy libraries


    Enter View Transitions

    The View Transition API changes the abstraction.

    Instead of animating elements manually, you tell the browser:

    “I’m about to change the UI. You handle the transition.”


What It Actually Does

At a high level, the browser:

  1. Takes a snapshot of the old UI

  2. Applies your DOM update

  3. Takes a snapshot of the new UI

  4. Animates between them

This happens at the browser compositor level
—not inside your React tree or CSS layout.

That’s the key difference.


Important: What View Transition API Is NOT

Let’s clear the biggest misconception:

View Transition API is NOT an extension of CSS transitions

It does not animate:

width
height
position
opacity

directly on DOM elements.

Instead:

It creates visual snapshots and animates them using keyframes at the compositor level

This is why:

  • it feels smoother

  • it avoids layout thrashing

  • it works across page navigations


Why This Matters?

Traditional animation:

DOM → Layout → Paint → Composite

View Transition:

Snapshot → Composite Animation

No layout recalculation during animation.

Result:

✔ smoother animations
✔ less jank
✔ better performance

The Core API

The entry point is simple:

document.startViewTransition(() => {
  // your UI update here
})

This tells the browser:

“Capture before and after, then animate between them.”


What Happens Internally?

When you call it:

  1. Browser captures current frame

  2. Runs your update function

  3. Captures new frame

  4. Creates pseudo elements:

::view-transition-old(root)
::view-transition-new(root)
  1. Animates between them

You can control this with CSS.


Basic Example

document.startViewTransition(() => {
  setPage('product')
})

Then in CSS:

::view-transition-old(root) {
  animation: fadeOut 0.3s ease;
}

::view-transition-new(root) {
  animation: fadeIn 0.3s ease;
}

This Changes How You Think About Animations

Before:

animate individual components

Now:

animate entire UI state changes

This is a mental shift.


Shared Element Transitions

This is where it gets powerful.

You can link elements across states:

.card {
  view-transition-name: product-card;
}

Now the browser understands:

“This element in old view = same element in new view”

And animates it seamlessly.


SPA vs MPA

The API works in both:

SPA (React, Next.js)

document.startViewTransition(() => {
  navigate('/product')
})

Browser handles navigation transitions automatically (where supported).


Why This API Exists?

Historically:

  • SPA transitions → complex JS

  • MPA transitions → almost impossible

View Transitions unify both.

They reduce:

manual DOM work
animation bugs
sync issues

React’s Experimental <ViewTransition>

React is trying to make this even easier.

import { ViewTransition } from 'react';

<ViewTransition>
  <Page />
</ViewTransition>

What React Is Doing Under the Hood?

React:

  • automatically assigns view-transition-name

  • groups elements

  • triggers transitions during state updates

You don’t manually call startViewTransition.


Important Behavior

React triggers transitions only when updates happen inside:

startTransition()
Suspense
useDeferredValue

Not every state update triggers animation.


Types of Transitions in React

React categorizes transitions:

enter
exit
update
shared

Each can be customised.


Example

<ViewTransition enter="slide-in" exit="fade-out">
  <ProductCard />
</ViewTransition>

Why This Is Powerful?

Instead of:

manually syncing animations across components

You get:

automatic view-level transitions

Limitations (Important)

This API is powerful, but not magic.

1. It’s still evolving

  • React version is experimental

  • Some browsers still catching up.


2. Debugging is harder

Because animations happen:

outside your DOM
inside compositor

3. Not everything animates perfectly

  • layout shifts can break continuity

  • shared elements need correct naming


The Real Mental Model

If you remember one thing:

View Transitions don’t animate elements
They animate snapshots of UI states


When Should You Use It?

Use it when:

route transitions
page navigation
list → detail views
UI state switches

Avoid it when:

micro animations (hover, button click)
fine-grained control needed

Conclusion

For years, web animations were:

“move this element from A to B”

Now the browser is finally giving us:

“move the entire experience from A to B”

That’s a big shift.