Skip to content

Add ReactDOM browser() API - #37143

Merged
gnoff merged 5 commits into
react:mainfrom
gnoff:jstory/react-dom-cache
Jul 30, 2026
Merged

Add ReactDOM browser() API#37143
gnoff merged 5 commits into
react:mainfrom
gnoff:jstory/react-dom-cache

Conversation

@gnoff

@gnoff gnoff commented Jul 29, 2026

Copy link
Copy Markdown
Collaborator

Summary

Adds a new API to react-dom called browser().

browser() returns a "usable" that will error during SSR and resolve during rendering in the browser. The purpose is to allow you to express the idea that a component should suspend on the server but not in the browser. The method is not available inside a react-server environment. This is a client only feature.

This is a react-dom API because the concept of browser doesn't apply generally to React itself.

This codifies a pattern that is common in some apps where you error during SSR to prevent rendering some component on the server and you end up suppressing the error that is reported in the client to avoid this appearing like a problem rather than intended behavior. Unfortunately this is not an option for many because hacking around to prevent errors from being logged is not practical for many

By making this a React API we enabled this common pattern in any React using library or application

import {use, Suspense} from 'react';
import {browser} from 'react-dom';

function BrowserOnly() {
  use(browser());
  return <ClientContent />;
}

function App() {
  return (
    <Suspense fallback={<Fallback />}>
      <BrowserOnly />
    </Suspense>
  );
}

It is an error to use(browser()) outside of a Suspense boundary because you cannot recover from the root. this restriction may be lifted in the future but is part of the current limitations of the API

Implementation

Deferring rendering to a downstream system is modeled in React already as recoverable errors. The idea is that in some environments you might not want to report something directly as an error because a later environment has an opportunity to recover from it without alerting the user to the mishap. This concept also shows up in RSC with halted references. They can "recover" in a later render by eventually resolving to some value.

To model the idea of "render in the browser" we are really just modeling an intentional recoverable error. However since you don't want to treat this kind of error as exceptional we intentionally suppress logging. Additionally since aborting a server render is semantically equivalent to "erroring" in every unfinished task we also support aborting with a browser() so you can describe ending a stream with intentional holes that won't be logged as errors in the browser when hydrating.

One interesting thing we do with this particular API is it returns an object that is isomorphic and it's the use or abort function that handles differing behaviors. This means you can create these objects in module scope and use them even in complex scenarios like server rendering inside the browser while React is rendering.

This implementation is flagged so we can disable the feature quickly if we decide to not ship this in a stable. It is going into React unprefixed for now because the semantics are clear and the utility is widely known.

Alternatives

We considered useBrowser() or a similar hook however this means you must call it unconditionally. There are use cases where props might influence whether you want to allow something to render during SSR or not. for instance you might have a data fetching library that accepts initial data on the server but if it doesn't receive initial data it falls back to browser only rendering.

Another consideration is a throwing function like just calling browser() would throw if called during an SSR render. The main reason we do not think this is a good idea is because you can then call this arbitrarily deep and the throw can be caught and might be suppressed accidentally. By making it a usable it can only be done in hooks or hook-like contexts.

@meta-cla meta-cla Bot added the CLA Signed label Jul 29, 2026
@github-actions github-actions Bot added the React Core Team Opened by a member of the React Core Team label Jul 29, 2026
@react-sizebot

react-sizebot commented Jul 29, 2026

Copy link
Copy Markdown

Comparing: 6cb4322...8cfb6c9

Critical size changes

Includes critical production bundles, as well as any change greater than 2%:

Name +/- Base Current +/- gzip Base gzip Current gzip
oss-stable/react-dom/cjs/react-dom.production.js +3.67% 7.19 kB 7.45 kB +4.51% 1.91 kB 1.99 kB
oss-stable/react-dom/cjs/react-dom-client.production.js +0.02% 616.42 kB 616.54 kB +0.05% 109.22 kB 109.27 kB
oss-experimental/react-dom/cjs/react-dom.production.js +3.67% 7.19 kB 7.46 kB +4.55% 1.91 kB 2.00 kB
oss-experimental/react-dom/cjs/react-dom-client.production.js +0.02% 687.63 kB 687.75 kB +0.04% 120.69 kB 120.73 kB
facebook-www/ReactDOM-prod.classic.js +0.05% 707.50 kB 707.83 kB +0.07% 124.11 kB 124.20 kB
facebook-www/ReactDOM-prod.modern.js +0.05% 697.82 kB 698.15 kB +0.08% 122.53 kB 122.63 kB
facebook-react-native/react-dom/cjs/ReactDOM-prod.js +3.78% 6.98 kB 7.25 kB +4.34% 1.89 kB 1.97 kB
facebook-react-native/react-dom/cjs/ReactDOM-profiling.js +3.78% 6.98 kB 7.25 kB +4.34% 1.89 kB 1.97 kB
oss-stable-semver/react-dom/cjs/react-dom.production.js +3.69% 7.16 kB 7.43 kB +4.51% 1.88 kB 1.97 kB
facebook-react-native/react-dom/cjs/ReactDOM-dev.js +3.61% 17.36 kB 17.99 kB +5.72% 3.69 kB 3.90 kB
oss-stable-semver/react-dom/cjs/react-dom.development.js +3.43% 18.30 kB 18.93 kB +5.43% 3.90 kB 4.12 kB
oss-stable/react-dom/cjs/react-dom.development.js +3.42% 18.33 kB 18.95 kB +5.34% 3.93 kB 4.14 kB
oss-experimental/react-dom/cjs/react-dom.development.js +3.42% 18.33 kB 18.96 kB +5.31% 3.94 kB 4.15 kB

Significant size changes

Includes any change greater than 0.2%:

Expand to show
Name +/- Base Current +/- gzip Base gzip Current gzip
facebook-react-native/react-dom/cjs/ReactDOM-prod.js +3.78% 6.98 kB 7.25 kB +4.34% 1.89 kB 1.97 kB
facebook-react-native/react-dom/cjs/ReactDOM-profiling.js +3.78% 6.98 kB 7.25 kB +4.34% 1.89 kB 1.97 kB
oss-stable-semver/react-dom/cjs/react-dom.production.js +3.69% 7.16 kB 7.43 kB +4.51% 1.88 kB 1.97 kB
oss-stable/react-dom/cjs/react-dom.production.js +3.67% 7.19 kB 7.45 kB +4.51% 1.91 kB 1.99 kB
oss-experimental/react-dom/cjs/react-dom.production.js +3.67% 7.19 kB 7.46 kB +4.55% 1.91 kB 2.00 kB
facebook-react-native/react-dom/cjs/ReactDOM-dev.js +3.61% 17.36 kB 17.99 kB +5.72% 3.69 kB 3.90 kB
oss-stable-semver/react-dom/cjs/react-dom.development.js +3.43% 18.30 kB 18.93 kB +5.43% 3.90 kB 4.12 kB
oss-stable/react-dom/cjs/react-dom.development.js +3.42% 18.33 kB 18.95 kB +5.34% 3.93 kB 4.14 kB
oss-experimental/react-dom/cjs/react-dom.development.js +3.42% 18.33 kB 18.96 kB +5.31% 3.94 kB 4.15 kB
oss-stable-semver/react-server/cjs/react-server.production.js +1.85% 151.27 kB 154.07 kB +2.08% 26.42 kB 26.97 kB
oss-stable/react-server/cjs/react-server.production.js +1.85% 151.27 kB 154.07 kB +2.08% 26.42 kB 26.97 kB
oss-experimental/react-debug-tools/cjs/react-debug-tools.production.js +1.83% 30.34 kB 30.90 kB +1.51% 5.88 kB 5.97 kB
oss-stable-semver/react-debug-tools/cjs/react-debug-tools.production.js +1.83% 30.34 kB 30.90 kB +1.51% 5.88 kB 5.97 kB
oss-stable/react-debug-tools/cjs/react-debug-tools.production.js +1.83% 30.34 kB 30.90 kB +1.51% 5.88 kB 5.97 kB
oss-experimental/react-debug-tools/cjs/react-debug-tools.development.js +1.82% 34.02 kB 34.64 kB +1.53% 6.00 kB 6.09 kB
oss-stable-semver/react-debug-tools/cjs/react-debug-tools.development.js +1.82% 34.02 kB 34.64 kB +1.53% 6.00 kB 6.09 kB
oss-stable/react-debug-tools/cjs/react-debug-tools.development.js +1.82% 34.02 kB 34.64 kB +1.53% 6.00 kB 6.09 kB
oss-experimental/react-server/cjs/react-server.production.js +1.80% 155.10 kB 157.90 kB +1.90% 27.25 kB 27.77 kB
oss-stable-semver/react-server/cjs/react-server.development.js +1.79% 217.71 kB 221.60 kB +1.58% 38.03 kB 38.63 kB
oss-stable/react-server/cjs/react-server.development.js +1.79% 217.71 kB 221.60 kB +1.58% 38.03 kB 38.63 kB
oss-experimental/react-server/cjs/react-server.development.js +1.75% 222.80 kB 226.69 kB +1.61% 39.00 kB 39.62 kB
oss-experimental/react-markup/cjs/react-markup.production.js +1.08% 252.44 kB 255.16 kB +1.16% 46.64 kB 47.18 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.production.js +1.04% 260.27 kB 262.97 kB +1.14% 47.81 kB 48.36 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.production.js +1.04% 260.30 kB 263.00 kB +1.13% 47.84 kB 48.38 kB
facebook-www/ReactDOMServerStreaming-prod.modern.js +1.02% 274.31 kB 277.11 kB +1.02% 49.90 kB 50.41 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.node.development.js +1.02% 416.35 kB 420.60 kB +1.03% 75.01 kB 75.78 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.development.js +1.02% 416.36 kB 420.60 kB +1.03% 75.01 kB 75.78 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.node.development.js +1.02% 416.38 kB 420.62 kB +1.03% 75.03 kB 75.81 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.development.js +1.02% 416.38 kB 420.62 kB +1.03% 75.03 kB 75.81 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.production.js +1.01% 270.94 kB 273.67 kB +1.07% 49.52 kB 50.05 kB
oss-experimental/react-markup/cjs/react-markup.development.js +1.00% 403.89 kB 407.92 kB +0.95% 72.97 kB 73.66 kB
facebook-www/ReactDOMServer-dev.modern.js +0.99% 427.49 kB 431.74 kB +1.02% 76.42 kB 77.19 kB
facebook-www/ReactDOMServerStreaming-dev.modern.js +0.99% 433.92 kB 438.22 kB +0.92% 77.48 kB 78.19 kB
facebook-www/ReactDOMServer-dev.classic.js +0.99% 430.94 kB 435.20 kB +1.01% 77.02 kB 77.80 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.node.development.js +0.98% 432.03 kB 436.28 kB +0.99% 77.29 kB 78.06 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.development.js +0.98% 432.03 kB 436.28 kB +0.99% 77.29 kB 78.06 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.development.js +0.98% 395.09 kB 398.95 kB +0.93% 74.65 kB 75.34 kB
oss-stable/react-dom/cjs/react-dom-server.bun.development.js +0.98% 395.17 kB 399.03 kB +0.93% 74.68 kB 75.37 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.production.js +0.96% 288.77 kB 291.55 kB +1.03% 52.44 kB 52.98 kB
oss-stable/react-dom/cjs/react-dom-server.edge.production.js +0.96% 288.85 kB 291.62 kB +1.03% 52.47 kB 53.01 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.development.js +0.96% 446.21 kB 450.49 kB +0.87% 79.26 kB 79.95 kB
oss-stable/react-dom/cjs/react-dom-server.browser.development.js +0.96% 446.28 kB 450.56 kB +0.87% 79.31 kB 80.00 kB
oss-stable-semver/react-dom/cjs/react-dom-server.edge.development.js +0.96% 446.99 kB 451.27 kB +0.87% 79.44 kB 80.13 kB
oss-stable/react-dom/cjs/react-dom-server.edge.development.js +0.96% 447.06 kB 451.35 kB +0.86% 79.49 kB 80.18 kB
oss-stable-semver/react-dom/cjs/react-dom-server.bun.production.js +0.96% 284.10 kB 286.82 kB +1.07% 50.01 kB 50.54 kB
oss-stable/react-dom/cjs/react-dom-server.bun.production.js +0.96% 284.18 kB 286.89 kB +1.07% 50.03 kB 50.57 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.development.js +0.95% 411.01 kB 414.90 kB +0.92% 77.23 kB 77.94 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.production.js +0.94% 297.02 kB 299.83 kB +1.06% 52.28 kB 52.83 kB
oss-stable/react-dom/cjs/react-dom-server.node.production.js +0.94% 297.10 kB 299.90 kB +1.06% 52.30 kB 52.86 kB
oss-stable-semver/react-dom/cjs/react-dom-server.node.development.js +0.94% 453.24 kB 457.52 kB +0.87% 79.26 kB 79.95 kB
oss-stable/react-dom/cjs/react-dom-server.node.development.js +0.94% 453.32 kB 457.60 kB +0.86% 79.32 kB 80.00 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.production.js +0.94% 302.51 kB 305.36 kB +1.06% 54.62 kB 55.20 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.development.js +0.93% 464.39 kB 468.72 kB +0.87% 81.88 kB 82.59 kB
oss-experimental/react-dom/cjs/react-dom-server.edge.development.js +0.93% 465.40 kB 469.73 kB +0.88% 82.10 kB 82.82 kB
oss-experimental/react-dom/cjs/react-dom-server.bun.production.js +0.93% 297.01 kB 299.76 kB +1.06% 52.03 kB 52.58 kB
oss-experimental/react-dom/cjs/react-dom-server.node.development.js +0.92% 471.15 kB 475.47 kB +0.84% 81.91 kB 82.59 kB
oss-experimental/react-dom/cjs/react-dom-server.node.production.js +0.92% 310.42 kB 313.26 kB +1.09% 54.44 kB 55.03 kB
oss-stable-semver/react-dom/cjs/react-dom-server-legacy.browser.production.js +0.85% 255.08 kB 257.24 kB +0.93% 45.80 kB 46.22 kB
oss-stable/react-dom/cjs/react-dom-server-legacy.browser.production.js +0.85% 255.11 kB 257.27 kB +0.93% 45.83 kB 46.25 kB
facebook-www/ReactDOMServer-prod.modern.js +0.83% 262.19 kB 264.38 kB +0.89% 46.70 kB 47.11 kB
facebook-www/ReactDOMServer-prod.classic.js +0.83% 264.52 kB 266.71 kB +0.92% 47.04 kB 47.47 kB
oss-experimental/react-dom/cjs/react-dom-server-legacy.browser.production.js +0.83% 265.17 kB 267.36 kB +0.90% 47.31 kB 47.73 kB
oss-stable-semver/react-dom/cjs/react-dom-server.browser.production.js +0.79% 282.88 kB 285.12 kB +0.88% 50.22 kB 50.66 kB
oss-stable/react-dom/cjs/react-dom-server.browser.production.js +0.79% 282.96 kB 285.19 kB +0.89% 50.25 kB 50.69 kB
oss-experimental/react-dom/cjs/react-dom-server.browser.production.js +0.78% 295.94 kB 298.25 kB +0.89% 52.13 kB 52.60 kB
oss-experimental/react-markup/cjs/react-markup.react-server.production.js +0.62% 368.16 kB 370.44 kB +0.70% 68.33 kB 68.81 kB
oss-experimental/react-markup/cjs/react-markup.react-server.development.js +0.51% 695.84 kB 699.38 kB +0.49% 123.20 kB 123.81 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js = 200.75 kB 200.26 kB = 35.09 kB 35.02 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js = 200.75 kB 200.26 kB = 35.09 kB 35.02 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.development.js = 200.75 kB 200.26 kB = 35.09 kB 35.02 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js = 200.71 kB 200.22 kB = 35.09 kB 35.03 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js = 200.71 kB 200.22 kB = 35.09 kB 35.03 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.development.js = 200.71 kB 200.22 kB = 35.09 kB 35.03 kB
oss-experimental/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.development.js = 199.33 kB 198.84 kB = 34.81 kB 34.74 kB
oss-stable-semver/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.development.js = 199.33 kB 198.84 kB = 34.81 kB 34.74 kB
oss-stable/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.development.js = 199.33 kB 198.84 kB = 34.81 kB 34.74 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js = 197.67 kB 197.18 kB = 34.55 kB 34.49 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js = 197.67 kB 197.18 kB = 34.55 kB 34.49 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.development.js = 197.67 kB 197.18 kB = 34.55 kB 34.49 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js = 195.84 kB 195.34 kB = 34.51 kB 34.44 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js = 195.84 kB 195.34 kB = 34.51 kB 34.44 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.node.development.js = 195.84 kB 195.34 kB = 34.51 kB 34.44 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js = 195.45 kB 194.96 kB = 34.44 kB 34.37 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js = 195.44 kB 194.95 kB = 34.44 kB 34.37 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.development.js = 195.39 kB 194.90 kB = 34.41 kB 34.34 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js = 195.03 kB 194.54 kB = 34.33 kB 34.26 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js = 195.02 kB 194.53 kB = 34.33 kB 34.26 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.development.js = 194.97 kB 194.48 kB = 34.30 kB 34.23 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js = 194.26 kB 193.77 kB = 34.27 kB 34.21 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js = 194.26 kB 193.77 kB = 34.27 kB 34.21 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.development.js = 194.26 kB 193.77 kB = 34.27 kB 34.21 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js = 194.22 kB 193.73 kB = 34.28 kB 34.21 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js = 194.22 kB 193.73 kB = 34.28 kB 34.21 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.development.js = 194.22 kB 193.73 kB = 34.28 kB 34.21 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js = 192.26 kB 191.77 kB = 33.77 kB 33.71 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js = 192.25 kB 191.76 kB = 33.77 kB 33.70 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.development.js = 192.20 kB 191.71 kB = 33.74 kB 33.68 kB
facebook-www/ReactFlightClient-dev.classic.js = 191.33 kB 190.84 kB = 33.76 kB 33.70 kB
facebook-www/ReactFlightClient-dev.modern.js = 191.33 kB 190.83 kB = 33.76 kB 33.70 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js = 190.88 kB 190.39 kB = 33.72 kB 33.66 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js = 190.88 kB 190.39 kB = 33.72 kB 33.66 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.development.js = 190.88 kB 190.39 kB = 33.72 kB 33.66 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js = 190.23 kB 189.74 kB = 33.35 kB 33.29 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js = 190.22 kB 189.73 kB = 33.35 kB 33.28 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.development.js = 190.17 kB 189.68 kB = 33.32 kB 33.26 kB
oss-experimental/react-client/cjs/react-client-flight.development.js = 184.46 kB 183.96 kB = 31.99 kB 31.94 kB
oss-stable/react-client/cjs/react-client-flight.development.js = 184.45 kB 183.96 kB = 31.99 kB 31.93 kB
oss-stable-semver/react-client/cjs/react-client-flight.development.js = 184.43 kB 183.93 kB = 31.97 kB 31.91 kB
oss-experimental/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js = 102.52 kB 102.07 kB = 20.90 kB 20.79 kB
oss-stable-semver/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js = 102.52 kB 102.07 kB = 20.90 kB 20.79 kB
oss-stable/react-server-dom-esm/esm/react-server-dom-esm-client.browser.production.js = 102.52 kB 102.07 kB = 20.90 kB 20.79 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js = 76.12 kB 75.66 kB = 14.70 kB 14.62 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js = 76.12 kB 75.66 kB = 14.70 kB 14.62 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.node.production.js = 76.12 kB 75.66 kB = 14.70 kB 14.62 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.production.js = 76.07 kB 75.62 kB = 14.70 kB 14.62 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.production.js = 76.07 kB 75.62 kB = 14.70 kB 14.62 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.node.production.js = 76.07 kB 75.62 kB = 14.70 kB 14.62 kB
oss-experimental/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.production.js = 74.95 kB 74.49 kB = 14.45 kB 14.38 kB
oss-stable-semver/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.production.js = 74.95 kB 74.49 kB = 14.45 kB 14.38 kB
oss-stable/react-server-dom-unbundled/cjs/react-server-dom-unbundled-client.node.production.js = 74.95 kB 74.49 kB = 14.45 kB 14.38 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.production.js = 72.88 kB 72.43 kB = 14.05 kB 13.98 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.production.js = 72.88 kB 72.43 kB = 14.05 kB 13.98 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.node.production.js = 72.88 kB 72.43 kB = 14.05 kB 13.98 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js = 71.67 kB 71.22 kB = 13.81 kB 13.73 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js = 71.67 kB 71.22 kB = 13.81 kB 13.73 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.node.production.js = 71.67 kB 71.22 kB = 13.81 kB 13.73 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js = 71.47 kB 71.02 kB = 13.98 kB 13.90 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js = 71.47 kB 71.02 kB = 13.98 kB 13.90 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.edge.production.js = 71.47 kB 71.02 kB = 13.98 kB 13.90 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.production.js = 71.43 kB 70.98 kB = 13.98 kB 13.91 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.production.js = 71.43 kB 70.98 kB = 13.98 kB 13.91 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.edge.production.js = 71.43 kB 70.98 kB = 13.98 kB 13.91 kB
oss-experimental/react-client/cjs/react-client-flight.production.js = 71.33 kB 70.86 kB = 12.72 kB 12.65 kB
oss-stable/react-client/cjs/react-client-flight.production.js = 71.32 kB 70.86 kB = 12.72 kB 12.65 kB
oss-stable-semver/react-client/cjs/react-client-flight.production.js = 71.30 kB 70.83 kB = 12.69 kB 12.62 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.production.js = 68.44 kB 67.99 kB = 13.39 kB 13.31 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.production.js = 68.44 kB 67.99 kB = 13.39 kB 13.31 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.edge.production.js = 68.44 kB 67.99 kB = 13.39 kB 13.31 kB
oss-experimental/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js = 64.28 kB 63.82 kB = 12.24 kB 12.17 kB
oss-stable-semver/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js = 64.28 kB 63.82 kB = 12.24 kB 12.17 kB
oss-stable/react-server-dom-webpack/cjs/react-server-dom-webpack-client.browser.production.js = 64.28 kB 63.82 kB = 12.24 kB 12.17 kB
oss-experimental/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.production.js = 63.91 kB 63.45 kB = 12.15 kB 12.08 kB
oss-stable-semver/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.production.js = 63.91 kB 63.45 kB = 12.15 kB 12.08 kB
oss-stable/react-server-dom-turbopack/cjs/react-server-dom-turbopack-client.browser.production.js = 63.91 kB 63.45 kB = 12.15 kB 12.08 kB
facebook-www/ReactFlightClient-prod.classic.js = 61.93 kB 61.48 kB = 11.99 kB 11.93 kB
facebook-www/ReactFlightClient-prod.modern.js = 61.93 kB 61.48 kB = 11.99 kB 11.93 kB
oss-experimental/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js = 62.14 kB 61.68 kB = 11.78 kB 11.72 kB
oss-stable-semver/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js = 62.14 kB 61.68 kB = 11.78 kB 11.72 kB
oss-stable/react-server-dom-esm/cjs/react-server-dom-esm-client.browser.production.js = 62.14 kB 61.68 kB = 11.78 kB 11.72 kB
oss-experimental/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.production.js = 61.95 kB 61.49 kB = 11.75 kB 11.68 kB
oss-stable-semver/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.production.js = 61.95 kB 61.49 kB = 11.75 kB 11.68 kB
oss-stable/react-server-dom-parcel/cjs/react-server-dom-parcel-client.browser.production.js = 61.95 kB 61.49 kB = 11.75 kB 11.68 kB

Generated by 🚫 dangerJS against 8cfb6c9

@gnoff
gnoff force-pushed the jstory/react-dom-cache branch 11 times, most recently from b818d42 to dba2ef2 Compare July 30, 2026 13:50
@gnoff
gnoff force-pushed the jstory/react-dom-cache branch 11 times, most recently from 54c34cb to 6a1614c Compare July 30, 2026 18:16
Export browser() from the client-capable react-dom entry points while omitting it from the react-server condition, so importing it into a Server Component remains a compile-time error.

Model the opaque result as a React recoverable Error branded with Symbol.for("react.recoverable"). Fiber is the final renderer and continues through recoverables without producing a value, while Fizz defers them to a downstream renderer.

When Fizz encounters use(browser()), eagerly capture an error at the use() site whose cause is the Error created by browser(), stash it, and throw a private sentinel to unwind the render. A Suspense boundary consumes that sentinel silently; if it reaches the root, substitute the stashed use-site error so the primary stack points to use() and the cause points to browser().

Encode the silent Fizz recovery with the internal empty digest and suppress the expected hydration report without reserving an ordinary userspace digest. In development, serialize a renderer-neutral deferral breadcrumb and component stack without exposing the sentinel stack. Directly throwing the browser() value remains a normal reported error because the recovery behavior is defined by use().

Cover the public browser API in Fiber, Fizz, hydration, root-fatal, stack and cause, direct-throw, development breadcrumb, production, WWW, digest, and module-scope scenarios.
@gnoff
gnoff force-pushed the jstory/react-dom-cache branch from 6a1614c to b0f262c Compare July 30, 2026 18:20
Treat a recoverable passed to abort() as a request to client render every unfinished Suspense boundary. These boundaries use the same silent wire signal as use(browser()), so neither the server onError callback nor the client's onRecoverableError callback is invoked.

If the abort happens before the shell completes, report the same fatal root error as use(browser()) outside Suspense, with the browser() value as its cause.

Add public streaming and hydration coverage for multiple pending boundaries and for the pre-shell fatal case. Also gate DEV-only wire diagnostics correctly and fix Flow refinements exposed by adding recoverables to Usable.
Add an enableBrowserAPI kill switch around the browser export while leaving it enabled in every feature flag fork. This provides a stable-release escape hatch without changing the recoverable rendering behavior when the API is enabled.

Mark the browser-specific public API tests with the same gate so disabling the export remains a supported test configuration.
@gnoff
gnoff force-pushed the jstory/react-dom-cache branch from 002b62d to 3d891e4 Compare July 30, 2026 19:02
gnoff added 2 commits July 30, 2026 12:59
Describe the recoverable transition as an explicit request so the development breadcrumb applies to both use(browser()) and abort(browser()).

Remove the test's direct inspection of hidden Suspense template metadata; the public behavior is already covered by the rendering and recovery assertions.
Keep the component-specific message for recoverables raised by use(browser()), and encode a separate message when abort(browser()) moves pending boundaries to client rendering.

Mark recoverable aborts as aborted in both normal and replay paths so boundary encoding can reliably select the abort-specific diagnostic.
@gnoff
gnoff merged commit 15f7cd6 into react:main Jul 30, 2026
238 checks passed
@gnoff
gnoff deleted the jstory/react-dom-cache branch July 30, 2026 20:15
Emasoft added a commit to Emasoft/ai-maestro-integrator-agent that referenced this pull request Aug 18, 2026
…T gate (TRDD-ONCGHA1Q)

The AI review refuted the premise of both the original card and b201375:
`gh pr view --json commits` returns commits CHRONOLOGICAL (oldest-first),
verified live against react/react#37143 and microsoft/vscode#200000
(committedDate ascends). The original code's COMMENT was wrong but its
COMPARISON was right; b201375 "normalized" on the comment's false premise
and inverted a behaviorally-correct gate for one commit.

Behavior now proven IDENTICAL to the original pre-fix code on all 6 table
cases (executed both, extracted verbatim from git show 50b044f). Net change
vs original: truthful comments pinning the VERIFIED ordering, and a test
suite whose inputs encode gh's real shape — not the comment's.

Why the audit missed it: the code comment, the audit worker, the card, and
the first test all shared ONE unverified premise; executing the function on
synthetic inputs derived from that premise "proved" the finding. A test
whose inputs inherit an unverified premise validates the premise, not the
code.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

CLA Signed React Core Team Opened by a member of the React Core Team

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants