View Transitions — Rethinking How UI Changes Are Animated
This Is Not Just Another Animation API

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:
Takes a snapshot of the old UI
Applies your DOM update
Takes a snapshot of the new UI
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:
Browser captures current frame
Runs your update function
Captures new frame
Creates pseudo elements:
::view-transition-old(root)
::view-transition-new(root)
- 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')
})
MPA (normal links)
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-namegroups 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.



