React ViewTransition Not Working? Every Fix (2026)
June 12, 2026
A React <ViewTransition> that silently refuses to animate almost always has one of four causes: the state update isn't wrapped in startTransition, the component isn't placed before any other DOM node, you're on stable React instead of a canary build, or the browser doesn't support the View Transition API.
TL;DR
React's <ViewTransition> component wraps the browser's View Transition API, but it only activates under specific conditions that aren't obvious from the happy-path demos. Plain setState never triggers it — only Transitions, Suspense reveals, and useDeferredValue do. It must sit above any DOM node in the component's output for enter/exit animations, and it ships only in React's Canary and Experimental channels, not in stable React 19.2.1 Work through the four causes below in order; one of them is your bug.
What you'll learn
- The four causes behind almost every silent
<ViewTransition>failure, in the order to check them - Why React only animates updates wrapped in
startTransition,<Suspense>, oruseDeferredValue - The DOM-placement rule that quietly disables enter and exit animations
- Which React versions and release channels actually include
<ViewTransition> - Current browser support for the View Transition API, including Safari and Firefox
- Why back-button navigations never animate, and the Navigation API fix
- How to customize animations with View Transition Classes, transition types, and JavaScript events
- How
<ViewTransition>fits into Next.js and React Router today
Why is my React ViewTransition not working?
In practice there are four causes, and they account for nearly every "nothing animates" report: a synchronous state update, wrong DOM placement, the wrong React release channel, or a browser without View Transition API support. Check them in that order — it's the fastest path to the culprit.
- The update is synchronous.
setStateoutside ofstartTransitioncommits immediately and opts out of animation by design.1 - The
<ViewTransition>sits below a DOM node. A single wrapping<div>above it disables enter/exit animations.1 - You're on stable React.
<ViewTransition>exists only in the Canary and Experimental channels; importing it from react 19.2 stable fails.1 - The browser lacks support. Without the View Transition API, React applies the DOM update with no animation — no error, no warning.2
There are also three sharp edges worth knowing even after animations work: React skips the transition entirely if flushSync lands mid-sequence, it waits up to 500ms for new fonts (and for wrapped images) before starting, and two mounted <ViewTransition> components sharing one name throw an error in development.1
Why does ViewTransition only animate inside startTransition?
This is the first thing to rule out. The fix is one wrapper:
import { ViewTransition, startTransition, useState } from 'react';
function Gallery() {
const [show, setShow] = useState(false);
return (
<>
<button
onClick={() => {
startTransition(() => { // without this: no animation
setShow((prev) => !prev);
});
}}>
Toggle
</button>
{show ? (
<ViewTransition enter="auto" exit="auto" default="none">
<img src="/hero.jpg" alt="" />
</ViewTransition>
) : null}
</>
);
}
Both pieces are required: <ViewTransition> marks what animates, startTransition marks when. Note that you should never call document.startViewTransition() yourself — React calls it behind the scenes and will interrupt any view transition it didn't start.1
Why won't my enter or exit animation trigger?
A <ViewTransition> only activates enter/exit if it is placed before any DOM node in the tree your component returns.1 If a <div> (or any host element) wraps it, enter and exit animations silently stop firing.
// 🚩 Broken: <div> above <ViewTransition> disables enter/exit
function Item() {
return (
<div>
<ViewTransition enter="auto" exit="auto">
<Video />
</ViewTransition>
</div>
);
}
// ✅ Works: ViewTransition comes first
function Item() {
return (
<ViewTransition enter="auto" exit="auto">
<div><Video /></div>
</ViewTransition>
);
}
The same rule shapes list reorder animations: items animate individually only when each item's <ViewTransition> is outside any wrapper DOM node, so avoid items.map(item => <div><Item /></div>) patterns if you want per-item movement.1 React is deliberately conservative here — the constraint exists to prevent too much or too little of the page from animating.
Which React version do you need for ViewTransition?
<ViewTransition> is only available in React's Canary and Experimental release channels — it is not part of any stable release, including the current React 19.2 line.1 It was announced in the React Labs post of April 23, 2025, and remains canary-gated as of June 2026.3
To try it outside a framework:
npm install react@canary react-dom@canary
import { ViewTransition, startTransition } from 'react';
If you import ViewTransition from stable React, you get an undefined binding or a build error rather than a helpful message — another easy-to-miss failure. Next.js App Router is the notable exception: it ships React canary builds, so the import works there once the framework flag is on (details below).4
Which browsers support the View Transition API?
Same-document view transitions — the kind React's component uses — are supported in Chrome 111+, Safari 18+, and Firefox 144+ (released October 2025), and are now Baseline Newly available.25 Cross-document transitions (for multi-page apps) are narrower: Chrome 126+, Edge 126+, and Safari 18.2+, with only partial support in Firefox 144+.6
Two practical consequences:
- Unsupported browsers degrade gracefully. The DOM update still applies; it just isn't animated. You don't need a feature-detection branch for correctness — only if you want an alternative animation.2
- Don't debug in the wrong browser. If you're testing in an older Firefox ESR or a pre-18 Safari, your code may be fine. Verify in a current Chrome first, then widen.
Accessibility note: React does not automatically disable these animations for users with prefers-reduced-motion — you're expected to tone them down yourself with the media query.1
Why doesn't the back button animate?
React intentionally skips view transition animations for navigations triggered by the legacy popstate event — which is what fires on the browser back button.1 A startTransition started from popstate must finish synchronously so scroll and form restoration work correctly, and that's incompatible with running an async view transition.
The official fix is to upgrade your router to the Navigation API, which doesn't carry the synchronous-restoration constraint.1 If you're on a framework router, this is the framework's job — check whether your router version uses the Navigation API before filing a bug about non-animating back navigations.
How do you customize ViewTransition animations?
You get three layers of control: View Transition Class props for CSS-driven animation, transition types for context-dependent variants, and event callbacks for full JavaScript control via the Web Animations API.1
View Transition Classes. Pass a class to enter, exit, update, share, or default, then target it with view-transition pseudo-selectors:
<ViewTransition enter="slide-in" default="slow-fade">
::view-transition-old(.slow-fade),
::view-transition-new(.slow-fade) {
animation-duration: 500ms;
}
Careful with default="none" — it turns off every trigger that isn't explicitly listed.1
Transition types. Call addTransitionType() inside the same startTransition to pick a variant, e.g. different slide directions for forward and back navigation:
<ViewTransition default={{
'navigation-back': 'slide-right',
'navigation-forward': 'slide-left',
}}>
JavaScript events. onEnter, onExit, onUpdate, and onShare hand you the old/new pseudo-elements so you can call .animate() directly. Always return a cleanup function so the browser can cancel interrupted animations.1
Does ViewTransition work with Next.js and React Router?
Yes, with caveats on both sides. Next.js has first-class but experimental integration: set experimental: { viewTransition: true } in next.config.js, and because App Router ships React canary, import { ViewTransition } from 'react' works out of the box — route navigations are Transitions, so animations activate on navigation automatically. Vercel marks the flag "not recommended for production" as of the current Next.js 16 docs.4
React Router takes a different approach that works on stable React: a viewTransition prop on <Link>, <NavLink>, and <Form> wraps the navigation in document.startViewTransition() directly — no React component involved.7 It first appeared as unstable_viewTransition in v6.17.0 and is stable in v7, alongside the useViewTransitionState hook for fine-grained styling. Don't mix the two models: if React's <ViewTransition> component is active, React expects to own startViewTransition calls.1
Bottom line
When a React <ViewTransition> does nothing, it's nearly always the transition wrapper, the placement rule, the release channel, or the browser. Fix those four and the API is dependable, with CSS classes, transition types, and event callbacks layered on top for polish. Treat it as what it is in 2026: a canary-channel feature that's production-adjacent in Next.js App Router and still experimental everywhere else. For more hands-on guides, see our walkthrough of cursor pagination in Postgres with Node.js for the data layer behind those animated lists, and our zero-downtime Kubernetes deployments guide for shipping the app without dropping requests.
Footnotes
-
React documentation,
<ViewTransition>reference (Canary) — https://react.dev/reference/react/ViewTransition ↩ ↩2 ↩3 ↩4 ↩5 ↩6 ↩7 ↩8 ↩9 ↩10 ↩11 ↩12 ↩13 ↩14 ↩15 ↩16 -
web.dev, "Same-document view transitions have become Baseline Newly available" — https://web.dev/blog/same-document-view-transitions-are-now-baseline-newly-available ↩ ↩2 ↩3
-
React Labs, "View Transitions, Activity, and more" (April 23, 2025) — https://react.dev/blog/2025/04/23/react-labs-view-transitions-activity-and-more ↩
-
Next.js documentation,
viewTransitionconfig (updated 2026-05-19) — https://nextjs.org/docs/app/api-reference/config/next-config-js/viewTransition ↩ ↩2 -
Can I use, View Transitions API (single-document) — https://caniuse.com/view-transitions ↩
-
Can I use, View Transitions (cross-document) — https://caniuse.com/cross-document-view-transitions ↩
-
React Router, "View Transitions" how-to — https://reactrouter.com/how-to/view-transitions ↩