The View Transitions API in 2026: Page Transitions Without Libraries
That hard cut when you change pages is not inevitable, and you do not need to load an animation library to fix it: with the View Transitions API the browser snapshots the old and the new state and composes the transition. Here is what you can ship today, with real examples.
For years, animating the move from one view to another meant picking between two bad options: adding a heavy dependency (Framer Motion, GSAP, a router plugin) or living with the browser's flash of blank. The View Transitions API hands that work to the rendering engine, and that changes the maths even for a multi-page site served from Blade templates.
What the View Transitions API Is and What It Solves
The API is built on one simple idea: when the DOM changes, the browser can capture an image of the previous state and another of the new one, then animate between them with CSS. No manual position maths, no cloning nodes by hand.
The Hard Cut We All Grew Up With
On a multi-page site, every link click destroys one document and mounts another. The browser paints the new page with no visual relationship to the old one, and the result is that abrupt cut the user reads as "the site loaded a different screen". In a single-page app the problem changes shape but does not go away: you animate the content swap yourself.
Read also
The Browser Takes the Snapshots, CSS Animates Them
With the API active, the browser builds a transition layer out of pseudo-elements: ::view-transition-old() for the snapshot that leaves and ::view-transition-new() for the one that arrives, grouped by ::view-transition-group(). A cross-fade is the default behaviour and any CSS animation can replace it. The developer defines the end state; the browser interpolates.
Two Scenarios: Same Page and Different Pages
Keep the two apart from the start, because they have different support and are triggered differently. Same-page transitions (tab switching, light and dark mode, opening a panel) are started with document.startViewTransition(). Cross-page transitions on a multi-page site are enabled with a CSS rule and need no JavaScript at all.
Browser Support as of September 2026
Same-Document Transitions: Baseline Since October 2025
Level 1 of the API has been Baseline Newly Available since October 14, 2025, when Firefox 144 completed support. In practice: Chrome and Edge since 111, Safari since 18, and Firefox from 133 with the full feature set from 144. The move to "widely available" is projected for 2028.
Cross-Document Transitions: Chromium and WebKit Lead, Firefox Still Behind
Cross-document transitions work in Chrome and Edge from 126, in Safari from 18.2 and in Samsung Internet from 27. Firefox does not offer them broadly yet, so treat them as progressive enhancement: if the engine does not support them, the navigation still happens, just without the animation.
Progressive Enhancement: No Support, Navigation Still Works
This is the reassuring part of the decision: nothing you write for the API is mandatory. The CSS rule that enables cross-page transitions is simply ignored by an engine without support, and the JavaScript that calls document.startViewTransition() can be wrapped in a plain existence check.
Same-Page Transitions
The Minimal Example: document.startViewTransition()
The simplest case wraps the DOM change in a method call. The browser captures the current state, runs the function and animates the result:
if (document.startViewTransition) {
document.startViewTransition(() => {
document.querySelector("#panel").classList.toggle("open");
});
} else {
document.querySelector("#panel").classList.toggle("open");
}What the Promises Give You: ready, updateCallbackDone and finished
The call returns an object with three promises that let you coordinate the rest of your code. updateCallbackDone fulfils when the update function has finished. ready fulfils once the snapshots are taken and the animation is about to start. finished arrives when the transition ends. If the transition is cancelled (for example, because two elements share the same name at snapshot time), ready rejects, so keep a catch around it rather than leaving the flow half-done.
Customizing the Animation with ::view-transition-old and ::view-transition-new
To replace the default cross-fade, animate the pseudo-elements. This block shortens the duration and controls the direction of the cross:
::view-transition-old(root) {
animation: 180ms ease-out both out;
}
::view-transition-new(root) {
animation: 240ms ease-in both in;
}
@keyframes out {
to { opacity: 0; }
}
@keyframes in {
from { opacity: 0; }
}Naming an Element So It Travels: view-transition-name
The detail that turns a correct transition into a memorable one is the shared element. When a thumbnail and the large image on the detail page declare the same view-transition-name, the browser understands they are the same object and moves it from one position to the other instead of cross-fading two screens. A name must be unique at snapshot time: if it repeats, the transition is cancelled.
Grouping Styles with view-transition-class and Automatic Names
Repeating view-transition-name across twenty cards in a grid is tedious. The view-transition-class property, from level 2 of the spec, lets several elements share transition styles without sharing a name, and the usual technique is to generate unique names from an index or the element id. The :active-view-transition pseudo-class also lets you style the root only while a transition is running.
Cross-Page Transitions for Multi-Page Sites, No JavaScript
The @view-transition { navigation: auto; } Rule on Both Pages
For a multi-page site, one CSS rule does all the work. It has to be present on both pages involved, the outgoing and the incoming one, and both must share the same origin:
@view-transition {
navigation: auto;
}With that in place, every link navigation between those pages is animated with a cross-fade. No routing changes, no HTML changes, no project JavaScript.
The Morph Trick: The Same view-transition-name in List and Detail
The general rule above can be refined. If the card in the listing and the image on the detail page share a name, the element travels between the two documents:
/* Listing page */
.card-3 { view-transition-name: card-3; }
/* Detail page */
.featured-image { view-transition-name: card-3; }The name must match across the two pages and be unique inside each one. This is the pattern that produces the sense of continuity that used to require a single-page router.
pageswap and pagereveal: Last-Second Tweaks
Two events let you adjust things right before or right after the snapshot. pageswap fires on the outgoing page, before the snapshot is taken, and is handy for assigning a name only to the element that will actually travel. pagereveal fires on the incoming page and exposes the transition in progress. Both events also fire when transitions are unsupported, so the code does not break.
Blade, Astro or Turbo: Where Each Piece Fits
A server-rendered site is the ideal case: add the rule to the main layout stylesheet and the whole navigation between routes is covered. There is no need to turn the site into a SPA or hydrate anything. If you later want a directional transition (say, a sideways shift when moving forward), pair it with the Navigation API, which provides the direction of the navigation.
When the Transition Does Not Run (and Your Code Looks Broken)
Same Origin, Reloads and bfcache
Cross-document transitions only apply to same-origin navigations. There is no transition on a page reload, none when returning through the back/forward cache (bfcache), and none when the redirect chain passes through another domain. On top of that, if the document is hidden (for instance, the tab is in the background), the browser skips the transition entirely.
Duplicate Names: The Transition Gets Cancelled
If two elements share the same view-transition-name at snapshot time, the browser cannot decide which one to animate and cancels the transition. It is an easy mistake to make in long listings and a hard one to spot on screen, because the visible result is simply that nothing animates.
Fixed Elements That Jump in the Snapshot
Navigation bars and other fixed-position elements are part of the snapshot and can appear to jump or stick. The usual fix is to give them their own name and animate them separately, or to keep them still with a minimal animation.
Accessibility: Reduced Motion and Focus
prefers-reduced-motion and How to Shorten the Animation
Anyone who has configured their system to reduce motion should not get a long transition. Shorten it until it is effectively instant:
@media (prefers-reduced-motion: reduce) {
::view-transition-group(*),
::view-transition-old(*),
::view-transition-new(*) {
animation-duration: 0.01ms !important;
}
}Never Hide a Context Change Behind an Animation
A transition is a visual hint, not an announcement. The page change must still happen immediately for screen readers and for keyboard focus, and no critical action should depend on the user seeing the animation.
A Complete Flow: From Gallery to Detail
With the pieces above you get a pattern that works in production with no dependencies. The @view-transition rule on both pages of the multi-page site animates navigation, and the shared name between the gallery thumbnail and the detail image makes the element travel. If the browser does not support cross-document transitions, the link still navigates and the site behaves exactly as before; if it does, the user sees continuity between the two screens.
Conclusion
The View Transitions API does not replace an animation library in every case, but it covers the most common work well: state changes, panel reveals and page navigation. The part that is already interoperable can be adopted today, and the parts that depend on the engine ship as progressive enhancement with no risk.
To go deeper, the blog has a guide on light CSS animations that improve user experience, a walkthrough of container queries and :has() and a look at Tailwind CSS v4.3.

