React 19.3: stable View Transitions and Fragment Refs, plus the new browser() API
On September 9, 2026, the React team published a post announcing that “React 19.3 is now available on npm”. It’s a minor version number, but not a minor release: two APIs that spent a long time in canary and experimental are finally stable, and react-dom gets an official way to keep a component out of server rendering. Here is what changed and what I think matters day to day.
View Transitions leave experimental
The <ViewTransition> component is now stable. It uses the browser’s View Transition API to animate elements as they enter, exit, move or resize. The core design point is that only updates marked as Transitions animate: startTransition, a <Suspense> reveal, or an update coming from useDeferredValue. Urgent updates, like typing into an input, do not trigger animations.
There are four animation types (enter, exit, update and share) and event props (onEnter, onExit, onShare, onUpdate) for anyone who wants imperative control over the animation. The addTransitionType function lets you record the cause of a transition, so the same state change can animate in different ways. The post’s own example is a slideshow:
function nextSlide() {
startTransition(() => {
addTransitionType('next');
setCurrentSlide(c => c + 1);
});
}
React also passes each type on to the browser, so you can target it in CSS with :active-view-transition-type(...). The Suspense integration is the most interesting detail: wrapping a boundary in <ViewTransition> animates the swap from fallback to final content, and wrapping images or fonts makes them suspend while they load.
The important caveat: for now it’s DOM only. According to the team, React Native and other platforms are in progress.
Fragment Refs and FragmentInstance
The second API to go stable is refs on <Fragment>. Pass a ref to a Fragment and you get a FragmentInstance that operates on the children’s DOM as a group, without adding a wrapper element. Its methods cover events (addEventListener, removeEventListener, dispatchEvent), focus (focus, focusLast, blur), observers (observeUsing to connect an IntersectionObserver or ResizeObserver) and measuring and scrolling (getClientRects, getRootNode, compareDocumentPosition, scrollIntoView).
In practice this solves an old problem: how many times have you added an extra div just to have somewhere to hang a ref or a visibility observer? For lists and layout components that can’t take an extra node, it’s a real improvement.
browser(), Trusted Types and Context in Server Components
In react-dom, the new piece is browser(). Calling use(browser()) makes the component suspend on the server, so the HTML ships with the nearest Suspense fallback, and on the client it doesn’t suspend, rendering normally after hydration:
import { use } from 'react';
import { browser } from 'react-dom';
function Component() {
use(browser());
// ...
}
According to the post, the call can be conditional. It’s the official way to say “this only makes sense in the browser” without workarounds based on useEffect and a mounted flag.
Another security change: React now passes values to DOM APIs without coercing them to strings. That lets TrustedHTML, TrustedScript and TrustedScriptURL objects reach the browser intact, so sites enforcing the require-trusted-types-for 'script' CSP now work with React.
In Server Components, you can now render a Context imported from a 'use client' module directly, with no intermediate Provider component.
Smaller changes worth your attention
The “other notable changes” list has items that can affect existing apps:
- Transitions now render independently, so a slow Transition no longer holds up unrelated ones.
- In Strict Mode, effects are now double-invoked during hydration too, matching client-rendered roots. If you have effects that can’t tolerate running twice, this may surface now.
react-domadds support for theonFullscreenChangeandonFullscreenErrorevents, the SVGmaskTypeproperty andfetchPriorityon module resources.- On the server side, Flight now supports
<Activity>and transportsError.causeto the client.
There’s also a solid list of bug fixes, including useDeferredValue getting stuck on an old value and <ViewTransition> crashes in Mobile Safari.
My take
React 19.3 is less about novelty and more about consolidation. View Transitions and Fragment Refs had been in experimentation for quite a while; now you can use them in production with a stable API guarantee. If you use a framework, the shortest path to these features will probably be the next framework release that bundles 19.3.
My practical advice: before upgrading, run your tests in Strict Mode with an eye on hydration, because double-invoked effects are exactly the kind of change that exposes latent bugs. And if you run a Trusted Types CSP and had given up on React because of it, it’s worth another look.