# 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:

```plaintext
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:

```plaintext
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:

```plaintext
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:

```plaintext
DOM → Layout → Paint → Composite
```

View Transition:

```plaintext
Snapshot → Composite Animation
```

No layout recalculation during animation.

Result:

```plaintext
✔ smoother animations
✔ less jank
✔ better performance
```

* * *

## The Core API

The entry point is simple:

```javascript
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:
    

```css
::view-transition-old(root)
::view-transition-new(root)
```

5.  Animates between them
    

You can control this with CSS.

* * *

## Basic Example

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

Then in CSS:

```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:

```plaintext
animate individual components
```

Now:

```plaintext
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:

```css
.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)

```javascript
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:

```plaintext
manual DOM work
animation bugs
sync issues
```

* * *

## React’s Experimental `<ViewTransition>`

React is trying to make this even easier.

```javascript
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:

```plaintext
startTransition()
Suspense
useDeferredValue
```

Not every state update triggers animation.

* * *

## Types of Transitions in React

React categorizes transitions:

```plaintext
enter
exit
update
shared
```

Each can be customised.

* * *

## Example

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

* * *

## Why This Is Powerful?

Instead of:

```plaintext
manually syncing animations across components
```

You get:

```plaintext
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:

```plaintext
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:

```plaintext
route transitions
page navigation
list → detail views
UI state switches
```

Avoid it when:

```plaintext
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.
