Guides · · Maxwell Prehoda
12 Page Transition Examples, From One Line of CSS to Award-Site Wipes
In 2026 the first page transition to try is the one the browser gives you. Add `@view-transition { navigation: auto; }` to the CSS of two same-origin pages and Chrome, Edge and Safari crossfade between them on a normal link click, with no JavaScript. From there you can name elements so a thumbnail grows into a hero, slide pages by direction, or hand the whole thing to a library like Barba.js when you want the agency-style wipes you see on award sites.
The 12 examples below run from that one-line version to full routing libraries, each with the case it fits, the stack it needs and its real limits. Ten are other people's tools and demos; two are ours. Most entries have a live demo from our directory showing the same motion as copyable CSS.
1. Chrome's View Transitions demo gallery: Best for seeing what the API can do before you build
Platform: Free demos, SPA and MPA versions
The Chrome team's demo site is the best page transition gallery on the web right now, because every demo comes in single-page and multi-page versions you can compare. Pagination slides the page by navigation direction. Stack Navigator recreates a chat app's push and pop. Profiles goes from an overview to a detail page. Video Zoom enlarges a video while it keeps playing. Circle reveals the next view through a growing clip-path circle.
Read them for the patterns, not the code: direction-aware slides for sequences, a shared element for list-to-detail, and a reveal shape for a mode change. Those three cover nearly every page transition a product needs.
Our Circle Reveal keyframes below are the same iris idea in plain CSS: a clip-path circle grows from the center while the content inside settles from a slight zoom.
Watch out for: Several demos use the Navigation API and view-transition-class, which are newer than the core API. Check support for each feature you copy, not just for view transitions in general.
2. Cross-document view transitions: Best for multi-page sites that want transitions with no JS
Platform: CSS only, Chrome and Edge 126, Safari 18.2
For a classic multi-page site, both pages opt in with `@view-transition { navigation: auto; }` and the browser handles the rest on same-origin navigations. By default the old page's snapshot fades from opacity 1 to 0 while the new one fades in; elements that change size or position get a scale or movement animation if you give them a `view-transition-name` on both pages.
Customise it with the `::view-transition-old(root)` and `::view-transition-new(root)` pseudo-elements, or name a header so it stays put while the content changes. The `pageswap` and `pagereveal` events let you set names at the last moment, for example only on the card that was clicked.
Our Fade In Left below is a good keyframe for the incoming page: it glides in on an expo ease-out while a shorter linear fade runs alongside, so the opacity is done before the motion settles.
Watch out for: Chrome's docs list no Firefox support for cross-document transitions yet. That is fine as progressive enhancement, since those visitors just get a normal navigation, but do not build anything that depends on the animation.
3. Same-document view transitions: Best for single-page apps switching views in place
Platform: JavaScript API, Chrome 111, Safari 18, Firefox 144
In a single-page app you wrap the DOM update in `document.startViewTransition()`. The browser snapshots the old state, runs your update, and animates from one to the other. Chrome's docs list support in Chrome and Edge 111, Safari 18 and Firefox 144, which makes this the most widely supported way to animate a route change without a library.
Element names must be unique among rendered elements at the same time, or the transition is skipped. MDN notes the `match-element` keyword, which assigns unique names automatically when you want every item in a list to animate to its new position.
Our Slide In Left below shows the drawer-style curve that suits a forward navigation: fast out of the gate, then a long glide into place.
Watch out for: Always feature-detect startViewTransition and run the update directly when it is missing. A missing check turns a cosmetic effect into a broken route.
4. Astro ClientRouter: Best for content sites and docs built with Astro
Platform: Astro, built in
Astro wraps view transitions in a few directives. Add the `ClientRouter` component to a shared layout and navigations become client-side with a fade by default. `transition:animate` switches between `fade`, `slide`, `initial` and `none` or takes your own keyframes, `transition:name` pairs elements across pages, and `transition:persist` keeps an island and its state alive across navigations, which is how you keep a media player or a half-filled form alive while the page changes.
It is also careful in the places people forget: animations are disabled when the user has `prefers-reduced-motion` set, the router announces the new page title to assistive technology, and a `fallback` option controls what browsers without support get. If you only want the native cross-document version, Astro's docs note you can skip ClientRouter entirely.
Watch out for: With ClientRouter, bundled scripts run only once. Code that sets up a page on load must listen for astro:page-load, or it silently stops working after the first navigation.
6. React ViewTransition component: Best for React apps animating Suspense and route updates
Platform: React, canary at time of writing
React's `<ViewTransition>` component wraps the browser API and calls `startViewTransition` for you. It only activates for updates inside `startTransition`, `<Suspense>` or `useDeferredValue`, so a plain `setState` will not animate. React decides whether a boundary is entering, exiting, updating or shared, and with no configuration you get the browser's crossfade.
Shared elements use a `name` prop: give a thumbnail and a hero the same name and the image morphs between them. You can pass CSS class names for `enter` and `exit` and style them with view transition pseudo-elements, or animate with the Web Animations API in `onEnter` and `onExit` callbacks.
Watch out for: The React docs say React does not disable these animations for prefers-reduced-motion, so add the media query yourself. The reference examples pin a 19.3 canary, so check the release notes before production use.
7. Barba.js: Best for agency and portfolio sites with custom wipes
Platform: JavaScript, about 7 kB, MIT license, v2
Barba has long been a favourite for studio and portfolio sites. It is small (the README says 7 kB minified and compressed), written in TypeScript with promises, and turns a multi-page site into one that swaps content without a full reload. Transitions are objects with `leave` and `enter` hooks, rules pick which transition runs for which navigation, and sync mode decides whether leave and enter play together or one after another.
A common Barba pattern is a solid panel that wipes across the screen, covers the swap and leaves. The Barba showcase collects sites built with it.
Our Block Swipe Reveal below is that wipe at the scale of a headline, in pure CSS: a bar scales in from the left and out to the right, and the text is there when it passes.
Watch out for: Because Barba swaps content without a full page load, analytics page views, focus, scroll position and third-party scripts on the new page all need hooks. Budget time for that, not just for the animation.
8. swup: Best for server-rendered sites that want CSS-timed transitions
Platform: JavaScript, MIT license, v4
swup describes itself as a page transition library for server-rendered websites. It manages the page load lifecycle, updates the URL and history, manages scroll position, and times the swap by detecting your CSS transitions and animations, so the motion itself stays in your stylesheet. Pages are cached, and a preload plugin fetches them in the background.
The plugin list is what makes it practical: official fade, slide and overlay themes, a head plugin that updates meta tags and stylesheets, a JS plugin for script-driven animations, an accessibility plugin, and a progress bar for slow loads.
Our Top Page Loading Bar below is the CSS version of that progress bar: the thin glowing bar that runs along the top of the page while a route loads.
Watch out for: Meta tags and page-specific stylesheets in the head are the head plugin's job, and JavaScript-driven animations need the JS plugin. Decide which plugins you need before you build, not after the first broken page.
9. Taxi.js by Unseen Studio: Best for teams moving off the unmaintained Highway.js
Platform: JavaScript, PJAX-style
Taxi.js was created by Jake Whiteley with feedback from the Okay Dev community and is brought to you by Unseen Studio. It replaces Highway.js, which is no longer maintained, and keeps its renderer and transition model: renderers handle what a page does when it loads, transitions handle how it arrives.
The useful additions are the boring ones: URL-based routing so different links get different transitions, a page cache that preserves DOM changes (handy for search results), preloading, navigation blocked during an active transition by default, correct content for 301 redirects, and support for view transitions.
Watch out for: Its attributes are data-taxi, data-taxi-view and data-taxi-ignore, and several Highway methods were renamed or removed. A Highway migration is a small rewrite, not a drop-in swap.
10. Awwwards Transitions collection: Best for inspiration from agency and portfolio sites
Platform: Website gallery, free to browse
Awwwards tags sites known for their transitions, and the collection runs to several pages of studio, portfolio and brand sites. Browse it with a question in mind: what does the transition say? The best ones carry an element from one page to the next (a project image that becomes the case study hero) or use one consistent wipe that becomes part of the brand.
It is also a useful reality check. Some award sites hold the visitor for a second or more on every navigation, which is fine for a portfolio people visit once and wrong for a product people use daily.
Our Transitions Showreel below, made in our Animation Studio, cuts through eight of these moves: a hard cut, a diagonal wipe, an iris from a full stop, a whip pan, slats, a zoom through a letter O, a match cut and a tile flip.
Watch out for: Award sites often block input during long transitions. If you borrow a look, keep the navigation itself instant and let the animation play over content that is already loading.
11. Our Full Page Loading Overlay: Best for route changes that wait on slow data
Platform: Motions directory, free, pure CSS Ours
Every page transition eventually meets a slow network. This overlay covers the moment between a route change and its data: a translucent, blurred layer with a spinner and a message, positioned absolute by default and switchable to fixed to cover the whole viewport.
Pair it with any of the routers above: show it only if the next page has not arrived after a few hundred milliseconds, so fast navigations get the transition and slow ones get honest feedback instead of a frozen animation. For more waiting patterns see our loading animation examples.
Watch out for: Do not show it on every navigation. A loader that flashes for 100 ms on a fast route makes the site feel slower than no loader at all.
12. Our Light to Dark Theme Switch: Best for app-wide mode changes such as dark mode
Platform: Motion Prompts, free prompt with video Ours
Not every transition is a navigation. Switching theme changes every surface at once, which is exactly what the circle reveal in Chrome's demos is good at. This piece shows the idea in full: a day-planner app flips from light to dark through a crisp circle growing out of its sun-and-moon toggle, with every colour token remapped rather than inverted, then flips back.
The prompt is free to copy. Paste it into our Animation Studio to make your own version, or use it as the spec for a `startViewTransition` call that animates `clip-path` on `::view-transition-new(root)` from the toggle's position.
Watch out for: A full-screen circle reveal is a large, fast change in brightness. Keep it short and skip it entirely under prefers-reduced-motion.
How to choose a page transition
Match it to the relationship between pages
Sequential pages (steps, pagination, a stack of chat screens) want a direction-aware slide like Slide In Left. List to detail wants a shared element: name the card and the hero the same with view-transition-name, React's name prop or Astro's transition:name. Unrelated pages want a quick crossfade, which is what the browser does by default. Save wipes and reveals for brand moments and mode changes.
Match it to your stack
Multi-page site: cross-document view transitions with one CSS rule, then Barba.js, swup or Taxi.js if you need more control. Astro: ClientRouter. SvelteKit: onNavigate. React: the ViewTransition component on canary, or startViewTransition in your router. Whatever you pick, feature-detect it so unsupported browsers fall back to a normal navigation.
Match it to how often people navigate
A portfolio visited once can afford a second of theatre. A product used all day cannot: keep route transitions around 200 to 400 ms, never block clicks while they play, and show a loader such as our Top Page Loading Bar only when data is genuinely slow. Turn off the travel under prefers-reduced-motion; Astro does it for you, React and the raw API do not.
Add your first page transition today
If your site has multiple pages on one origin, add `@view-transition { navigation: auto; }` to the shared stylesheet, reload, and click a link in Chrome or Safari. That is a working page transition. Next, give your site header a `view-transition-name` so it stays still while the content fades, and set a slightly longer duration on `::view-transition-new(root)` if the default feels abrupt.
When you want something more distinctive, sketch it first: describe the wipe or reveal in our creator and get the CSS keyframes, or build the whole sequence in the Studio. For the dialog that often precedes a navigation, see our modal animation examples.
Write CSS for cross-document view transitions on a multi-page marketing site. Keep the header still with view-transition-name: site-header. The old page fades out over 150 ms; the new page fades in and rises 16px over 300 ms with cubic-bezier(0.2, 0.8, 0.2, 1). Product cards and their detail-page hero share a view-transition-name so the image grows into place. Under prefers-reduced-motion, use a plain 150 ms crossfade.
Common questions
How do I add page transitions to a website?
On a multi-page site with same-origin pages, add @view-transition { navigation: auto; } to the CSS of both pages. Chrome and Edge 126 and Safari 18.2 will crossfade between them on navigation. For single-page apps use document.startViewTransition, or the built-in support in Astro, SvelteKit or React. For custom wipes on any browser, use a library such as Barba.js, swup or Taxi.js.
Do view transitions work in all browsers?
Same-document view transitions are supported in Chrome and Edge 111, Safari 18 and Firefox 144, according to Chrome's documentation. Cross-document transitions are in Chrome and Edge 126 and Safari 18.2, and Chrome's docs list Firefox as not supporting them yet. Browsers without support simply navigate normally.
Are page transitions bad for performance or SEO?
Native view transitions do not change how pages load or what search engines see, because each page is still a normal document. Routing libraries that swap content with JavaScript can be fine for SEO when every URL also works as a full page load, but you must update titles, meta tags and analytics yourself or with plugins such as swup's head plugin. Long transitions that block input are a usability problem regardless.
How long should a page transition be?
For products people use repeatedly, about 200 to 400 ms. Portfolio and campaign sites can go longer because they are visited once, but navigation should never wait for the animation to finish.
Is Barba.js still maintained?
Barba's site and README list v2 as stable, and it is MIT licensed. Highway.js, an older alternative, is no longer maintained, and its successor is Taxi.js.