RAYAXIS

Blog

What we would turn on from React 19.3

October 3, 2026React · Next.js · Frontend · Web · Product

React 19.3 makes view transitions, fragment refs, and a browser-only render opt-out ordinary. Here is which of those we would put on a shipped screen.

All posts

React 19.3.0 reached npm on 9 September 2026. The React team's post the same day treats a few APIs as ready for ordinary code: a ViewTransition component, a ref on Fragment, use(browser()) from react-dom, and Trusted Types values that React will pass through to the DOM. A Server Component can also render a client Context directly, instead of through a wrapper that only forwards a prop.

We build web apps in React and Next.js from Lalitpur. A minor release is a dependency bump with a short list of decisions. These are the ones we would make.

Motion only when the update can wait

<ViewTransition> asks the browser's View Transition API to animate a piece of UI when it enters, leaves, updates, or moves under a shared name. The default is a cross-fade. Call addTransitionType inside the same startTransition as the state change when forward and back need different motion. A carousel and a multi-step form both have that problem. The destination can be the same kind of index either way. The animation should still know which button was pressed.

The trigger is the part that will fail a review. React animates this component when the update is a Transition: startTransition, a Suspense reveal, or useDeferredValue. An urgent setState updates the screen immediately and skips the animation. A CSS transition still owns hover and other updates that have to feel instant. <ViewTransition> marks work we already decided can take a frame.

Two places are enough. A list row that opens a detail panel, with the shared name set to the row id, when that navigation is already a transition. A stepped form, with addTransitionType('next') and addTransitionType('previous'), so the direction matches the control. Keep the wrapper on the piece that moves. The announcement says the component is DOM-only for now, with React Native support still in progress. Native screens stay on the animation tools they already use.

Same-document view transitions are available in Chrome and Edge from 111, Safari from 18, and Firefox from 144, per Can I use as checked on 3 October 2026. When a browser skips the animation, the UI still changes. That missing motion is an acceptable fallback. Shipping a second animation library beside it would mean two systems to keep in sync.

The announcement is the overview. The <ViewTransition> reference is the page to read before a route ships, including its notes on shared names. One card in a sandbox does not prove a page that has two of them.

A ref without an extra box

A normal ref points at one host node. A run of sibling headings, or a card from a library that does not forward ref, has no single node to attach to. A wrapping div gives you the ref and can break a grid or a flex layout that was already signed off.

In 19.3, Fragment accepts a ref. The resulting FragmentInstance works on the children as a group:

  • addEventListener, removeEventListener, and dispatchEvent cover the first-level nodes.
  • focus, focusLast, and blur walk nested children depth-first.
  • observeUsing and unobserveUsing connect an IntersectionObserver or a ResizeObserver.
  • getClientRects, getRootNode, compareDocumentPosition, and scrollIntoView measure or scroll those first-level children.

The helper worth writing is an in-view wrapper that must not add a box. The observer hangs off the fragment. The children keep their layout. We leave the third-party component alone. When we own the markup, a ref on a real element is still the clearer code. Fragment refs are for the case where an extra element would be a lie about the layout.

browser() leaves a hole in the HTML

Server rendering has to match the first client render. A map, a chart that reads localStorage, or a line that prints the device time zone cannot do that honestly. The usual patch is a mounted flag set in an effect, or a typeof window check that hydrates badly when the two trees differ.

browser comes from react-dom. use(browser()) suspends on the server and does not suspend in the browser. The HTML for that subtree is the nearest Suspense fallback. After hydration, the component renders as usual. The call may sit after a condition. If initialData is already in hand, skip browser() and keep the component in the document.

That split is the rule we would write in review. When the server has the data, render the data. browser() means the first HTML is the fallback. Product names, prices, and form fields belong in that server HTML. A time-zone chip beside a server-rendered event time can wait. The React post uses the same split: a known zone renders immediately, and the device zone waits for the browser.

Trusted Types, once the rest of the page agrees

Trusted Types block raw strings at sinks such as innerHTML when the response includes Content-Security-Policy: require-trusted-types-for 'script'. The browser expects a TrustedHTML, TrustedScript, or TrustedScriptURL produced by your policy. React used to coerce values with string concatenation before the DOM write, which turned those objects back into strings the browser rejects. React 19.3 passes them through.

Turn that CSP directive on when every other script on the page can satisfy it. Analytics snippets, a rich-text editor, and any code that assigns innerHTML are still in scope. This release removes one known blocker inside React. The page review is still ours.

Delete the provider that only forwards a prop

Server Components still cannot create context. They can import a Context from a 'use client' module and render <UserContext value={currentUser}> themselves. The client component that existed only to perform that hand-off can be deleted. createContext stays in the client module. The limit in the 19.3 post is the same limit as before.

How we would take the bump

Move react and react-dom together, both on 19.3.0. Read the changelog even if the new components stay unused. Transitions now render independently, so a slow one should no longer hold up an unrelated one. There are fixes for useDeferredValue sticking on an old value, and for context inside Suspense fallbacks. A screen that has been wrong in those spots might improve, and the bug might also move. Try one route, with the tests that already exist, then update the rest of the lockfile.

Check that the framework in that repo accepts 19.3 before changing versions. This marketing site currently locks React at 19.2.8. The 19.3 bump belongs on an application route first.

Sources

← Back to blog