View Transitions API: Native Page Animations
The browser now handles smooth page transitions natively. No libraries needed — just CSS and a few lines of JavaScript.
View Transitions API: Native Page Animations
Remember adding libraries just for page transitions? Those days are over. The browser does it natively now.

The Old Way
You needed Framer Motion, React Transition Group, or GSAP:
// 50KB+ of JavaScript for fade transitionsimport { AnimatePresence, motion } from "framer-motion";
function App() { return ( <AnimatePresence mode="wait"> <motion.div initial={{ opacity: 0 }} animate={{ opacity: 1 }} exit={{ opacity: 0 }} > {page} </motion.div> </AnimatePresence> );}The New Way
One function. Zero dependencies:
document.startViewTransition(() => { // Update the DOM however you want updatePage(newContent);});The browser handles the animation automatically.
How It Works
- Browser screenshots the current state
- Your callback updates the DOM
- Browser screenshots the new state
- Crossfades between them
// Navigation with smooth transitionasync function navigate(url) { const response = await fetch(url); const html = await response.text(); document.startViewTransition(() => { document.body.innerHTML = html; });}Custom Animations with CSS
The magic: you control everything with CSS.
/* Slow down the transition */::view-transition-old(root),::view-transition-new(root) { animation-duration: 0.5s;}
/* Slide instead of fade */::view-transition-old(root) { animation: slide-out 0.3s ease-out;}
::view-transition-new(root) { animation: slide-in 0.3s ease-out;}
@keyframes slide-out { to { transform: translateX(-100%); }}
@keyframes slide-in { from { transform: translateX(100%); }}Named Transitions
Animate specific elements independently:
/* Give elements a transition name */.hero-image { view-transition-name: hero;}
.page-title { view-transition-name: title;}Now the hero image and title animate separately from the page:
/* Hero scales and moves */::view-transition-old(hero),::view-transition-new(hero) { animation-duration: 0.4s; animation-timing-function: ease-out;}
/* Title slides up */::view-transition-new(title) { animation: slide-up 0.3s ease-out;}Live Demo
Framework Integration
Works with any framework. Here is React:
import { useNavigate } from "react-router-dom";
function Link({ to, children }) { const navigate = useNavigate(); function handleClick(e) { e.preventDefault(); document.startViewTransition(() => { navigate(to); }); } return <a href={to} onClick={handleClick}>{children}</a>;}Browser Support
- Chrome 111+
- Edge 111+
- Safari 18+
- Firefox: behind flag
Always feature-detect:
if (document.startViewTransition) { document.startViewTransition(() => update());} else { update(); // Fallback: instant update}Key Takeaways
- Zero dependencies — built into the browser
- CSS-powered — full control over animations
- Progressive enhancement — falls back gracefully
- Works everywhere — vanilla JS, React, Vue, Astro
Page transitions used to require heavy libraries. Now it is one function call. The platform keeps getting better.
---
Ship smoother experiences with less code. That is the web in 2026.
Stay Updated 📬
Get the latest tips and tutorials delivered to your inbox. No spam, unsubscribe anytime.