CSS View Transitions API (No Framework)

Page transitions without a framework

Page transitions used to need Barba.js or React Transition Group. The View Transitions API gives you cross-fades and shared-element motion with one JS call and CSS.

Old way 20+ lines
// barba.js or custom router transitionsimport Barba from '@barba/core';Barba.init({  transitions: [{    leave: ({ current }) => gsap.to(current.container, { opacity: 0 }),    enter: ({ next }) => gsap.from(next.container, { opacity: 0 })  }]});
Modern
8 lines
// JS: wrap DOM updatedocument.startViewTransition(() => {  document.body.innerHTML = newContent;});.hero {  view-transition-name: hero;}/* Optional: ::view-transition-old/new(hero) */
Newly available Since 2024 89% global usage

Since 2024 this feature works across the latest devices and browser versions. This feature might not work in older devices or browsers.

Works in all modern browsers. May need a fallback for older browsers.

111+
130+
18.2+
111+
click the button to trigger a view transition
🎨
View Transitions

One API

Wrap your DOM update in startViewTransition. Browser handles capture, transition, and paint.

Shared elements

view-transition-name links old and new elements. Morph between them with CSS.

Framework-agnostic

Works with vanilla JS, React, or any stack. No router lock-in.

Lines Saved
20+ → 8
No transition lib
Old Approach
Barba / React TG
Custom leave/enter hooks
Modern Approach
View Transitions API
Native capture and animate

How it works

Smooth page-to-page or view-to-view transitions usually meant a library that ran leave animations, swapped content, then ran enter animations. You managed state and timing yourself.

document.startViewTransition(callback) runs your callback (e.g. update the DOM), and the browser captures the before state, applies the update, captures the after state, then animates between them. Use view-transition-name on elements that should match across views for shared-element effects. Style with ::view-transition-old() and ::view-transition-new().

Always respect prefers-reduced-motion. Wrap transition animations in a @media (prefers-reduced-motion: no-preference) block, or use @media (prefers-reduced-motion: reduce) { ::view-transition-group(*) { animation: none; } } to disable transitions for users who have opted out of motion.

For same-document transitions the API is widely supported. Cross-document view transitions (navigating between full pages without a SPA) require the @view-transition { navigation: auto; } CSS rule and are still rolling out. If the API is unavailable, the callback still runs normally. The DOM update happens without animation, making this a zero-cost progressive enhancement.

ESC