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.
// 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 }) }]}); // JS: wrap DOM updatedocument.startViewTransition(() => { document.body.innerHTML = newContent;});.hero { view-transition-name: hero;}/* Optional: ::view-transition-old/new(hero) */ view transitions Browser Support
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.
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.
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.