The Journal

CSS & Layout3 min read

View Transitions API: Building Smooth Page Animations Without JavaScript

Learn how the View Transitions API enables native-feeling page transitions in web apps. Build cinematic route animations, shared element transitions, and smooth state changes with minimal code.

You want the new page to fade in instead of snapping. The old way: a motion library, AnimatePresence, and a fight with unmount timing. The new way is one function the browser already ships: it snapshots the old state, snapshots the new one, and animates between them in CSS.

One function

Wrap the DOM change that matters in document.startViewTransition(() => update()). The browser takes a before-and-after screenshot and crossfades them by default — you write no keyframes at all.

Everything inside the callback is the new state; everything before it is the old. The browser diffs the two frames and tweens between them for you.

That’s the entire entry point. In Next.js, turn on the experimental viewTransition flag and route changes pick it up automatically.

Name what moves

A crossfade is nice. A thing that flies from one spot to the next is the effect people remember. Give the same element a view-transition-name on both pages — say hero on a grid thumbnail and on the full image it turns into.

The browser matches them by name and animates position, size, and shape between the two. A grid photo morphs into a detail hero with zero position math from you.

Names must be unique on the page — two elements sharing hero at once will throw. Set it, run the transition, then clear it if the element sticks around.

Style and fall back

Style the transition with plain CSS on the ::view-transition-old and ::view-transition-new pseudo-elements — change the duration, swap the easing, trade the crossfade for a slide.

Keep durations short. 200–300ms reads as responsive; past 500ms it starts to feel like the app is stalling.

Support isn’t everywhere yet, and that’s fine. The callback runs either way; unsupported browsers just skip the animation and update instantly. Call document.startViewTransition?.(update) and nothing breaks.

Where it pays

Don’t transition everything. It earns its keep in a few specific spots:

  • A gallery thumbnail opening into its full detail view.
  • A list item expanding into a full page.
  • Tab or filter changes that reorder cards.

Use it there, leave the rest instant, and gate it behind reduced motion. It’s the rare polish that costs a few lines and reads like weeks of work.

Frequently asked questions

How does the View Transitions API work?
Wrap the DOM change in document.startViewTransition, and the browser snapshots the old and new states and crossfades between them in CSS with no keyframes. Unsupported browsers skip the animation and update instantly, so calling it with optional chaining means nothing breaks.
How do I animate an element flying between two pages?
Give the same element a view-transition-name on both pages, such as hero on a grid thumbnail and on the full image, and the browser matches them by name and animates position, size, and shape between them. Names must be unique on the page or the transition throws.
Can I use the View Transitions API in Next.js?
Yes. Turn on the experimental viewTransition flag in Next.js and route changes pick up native transitions automatically. Keep durations short, around 200 to 300ms, since past 500ms it starts to feel like the app is stalling, and gate the effect behind prefers-reduced-motion.