Blog / 01

React 19.3 Ships Stable ViewTransition and Fragment Refs

WebRestart

React 19.3.0 shipped on September 9, 2026. Two APIs that have spent well over a year behind the canary channel — <ViewTransition> and Fragment refs — are now in a stable minor, along with a new react-dom API called browser() and an opt-in Trusted Types integration. Nothing here is breaking; it is a minor on the 19.x line.

The practical headline for anyone building on Next.js: the animation APIs you could previously only reach through the App Router's canary React are now ordinary stable React. Next.js 16.3.4 declares a react peer range of ^18.2.0 || ^19.0.0, so 19.3.0 satisfies it without any override.

ViewTransition and addTransitionType

<ViewTransition> wraps React's concurrent rendering around the browser's View Transitions API. You give two elements on different screens the same name and the browser animates between their old and new positions instead of cutting.

The important constraint is what activates it. <ViewTransition> animations fire from Transitions, <Suspense> reveals and useDeferredValue — a plain setState does not trigger one. In Next.js, route navigations are transitions, so the animations activate on navigation with no wiring. addTransitionType ships alongside it, letting you tag a transition (forward vs. back, say) and branch your CSS on it.

The clearest evidence that this is a real status change is in Next.js's own documentation. The view-transitions guide on the v16.3.4 tag reads:

View transitions work in the App Router with no configuration. The App Router uses React canary releases, which contain all stable React 19 changes as well as newer features like ViewTransition. You do not need to install react@canary yourself.

The same file on canary now reads: "React 19.3 includes the <ViewTransition> component and addTransitionType API used in this guide." The canary caveat is gone. If you are on the Pages Router, or on plain React outside Next.js, this is the release that opens the API to you.

One browser note carried over from the Next.js guide: React's integration relies on transition types and view-transition-class, which need Chromium 125+ and recent Safari and Firefox. Without support the app works normally, it just does not animate.

Fragment refs

The second stable feature is smaller but removes a genuinely annoying pattern. You can now pass a ref to a Fragment and get back a FragmentInstance that operates on the fragment's first-level DOM children — no wrapper <div> added purely to hang a ref on.

FragmentInstance implements:

  • addEventListener / removeEventListener / dispatchEvent — across all first-level DOM children
  • focus / focusLast / blur — searching all nested children depth-first, not just direct children
  • observeUsing / unobserveUsing — attach or detach an IntersectionObserver or ResizeObserver

focus() is the one worth noticing: unlike element.focus(), it walks the subtree until it finds something focusable, which is exactly the behaviour every hand-rolled focus-management helper has been reimplementing.

There is a syntax caveat. You cannot use the <>...</> shorthand with a ref — import Fragment explicitly:

import { Fragment, useRef } from 'react'

const ref = useRef(null)
return <Fragment ref={ref}>{children}</Fragment>

browser(): marking a subtree browser-only

react-dom gains browser(), used inside use():

import { use } from 'react'
import { browser } from 'react-dom'

function Chart() {
  use(browser('Needs ResizeObserver.'))
  return <ExpensiveCanvas />
}

During server rendering this stops the component and leaves the nearest <Suspense> fallback in place; in the browser use(browser()) returns undefined and the component renders normally. Unlike the usual useEffect-plus-state dance, it is not reported as a recoverable hydration error. Three caveats from the reference: it must sit inside a <Suspense> boundary or the server render fails, in an RSC app it must be called from a Client Component, and calling browser() without passing it to use() does nothing. A matching onBrowserBailout option on the react-dom/server APIs lets you observe which subtrees deferred.

The change you get for free

Buried under "Notable changes" is one that needs no code:

Transitions now render independently instead of being entangled into a single render, so a slow transition no longer holds up unrelated ones.

That is #37290. If you have ever watched one slow server response stall an unrelated piece of UI, this is the fix, and it pairs directly with the prefetching work in Next.js 16.3's Instant Navigations.

Also landing: Trusted Types API integration (#35816), a DEV-only warning when a component looks like it was unblocked by calling use() conditionally, and a long run of Fast Refresh, Activity and Server Components fixes.

Upgrading

npm install react@19.3.0 react-dom@19.3.0

Read the release notes rather than the summaries — the 19.3.0 CHANGELOG entry and the GitHub release are the primary sources for everything above.


Thinking about adding view transitions to an existing App Router codebase, or unsure whether your React version is the vendored one or the one in your lockfile? Get in touch — auditing and upgrading Next.js applications is what we do.