browser - This feature is available in the latest Canary version of React

Canary

The browser API is currently only available in React’s Canary and Experimental channels.

Learn more about React’s release channels here.

browser lets you skip rendering part of a React tree on the server, leaving its nearest Suspense fallback in place until that content renders in the browser.

use(browser(reason?));

Reference

browser(reason?)

Call browser inside use to defer rendering until the component runs in the browser:

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

function BrowserOnly() {
use(browser('This component requires browser APIs.'));
return <ClientContent />;
}

During server rendering, use(browser()) stops rendering the component and displays the fallback of the closest <Suspense> boundary. During rendering in the browser, use(browser()) continues immediately so the component can render.

See more examples below.

Parameters

  • optional reason: A string that describes why React should defer rendering, or a function that returns a diagnostic value. Use a function for values that are expensive to create, such as () => new Error(...). React calls the function only when a server renderer consumes the value returned by browser, so the browser does not unnecessarily create the error or capture its stack. The server renderer attaches the resulting value as the cause of the Error passed to onBrowserBailout.

Returns

browser returns an opaque value. Pass this value to use in a component, or use it as the reason when aborting a server render. In the browser, passing this value to use returns undefined.

Caveats

  • browser is not available in a react-server environment. You can use it while server-rendering Client Components, but you cannot import it in a React Server Component.
  • A component that passes a value returned by browser to use during server rendering must have a <Suspense> boundary above it. Otherwise, the entire server render will fail.
  • Calling browser() by itself does not check the current environment or affect rendering. The behavior depends on whether you pass its return value to use during server or browser rendering. This means you can create the value at module scope and reuse it.
  • To defer a component, pass the value returned by browser to use. Do not throw the value directly.
  • A reason function is for diagnostics only. If it throws, React continues the browser-only rendering behavior and substitutes a generic reason.

Usage

Rendering content only in the browser

Call use with the value returned by browser to skip rendering a component on the server:

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

function BrowserOnlyEditor() {
use(browser('The editor requires browser APIs.'));
return <Editor />;
}

export default function Page() {
return (
<Suspense fallback={<p>Loading editor...</p>}>
<BrowserOnlyEditor />
</Suspense>
);
}

During server rendering, React includes the Loading editor... fallback in the HTML. When the app renders in the browser, use(browser()) continues immediately and React renders the Editor instead.

React treats this deferral as intentional. It does not report it to the server renderer’s onError callback or hydrateRoot’s onRecoverableError callback.

If JavaScript does not load, the fallback remains visible. Avoid deferring content that must be present in the initial HTML.


Conditionally rendering in the browser

Like other calls to use, use(browser()) can be called conditionally. For example, a component can render on the server when it receives initial data, but defer to the browser when that data is missing:

function Map({initialCenter}) {
if (initialCenter === null) {
use(browser('The map center is stored in the browser.'));
initialCenter = readCenterFromLocalStorage();
}

return <MapCanvas center={initialCenter} />;
}

On the server, use(browser()) prevents the browser-only readCenterFromLocalStorage call from running. In the browser, use(browser()) continues immediately, so the component reads the saved value and renders.


Reporting browser-only rendering on the server

Pass an optional reason to browser and provide onBrowserBailout to the server renderer to report browser-only rendering:

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

function BrowserOnlyEditor() {
use(browser(() => new Error('The editor requires a browser API.')));
return <Editor />;
}

const {pipe} = renderToPipeableStream(
<Suspense fallback={<p>Loading editor...</p>}>
<BrowserOnlyEditor />
</Suspense>,
{
onShellReady() {
pipe(response);
},
onBrowserBailout(error, errorInfo) {
logBrowserBailout(error.cause, errorInfo.componentStack);
}
}
);

When React successfully recovers by leaving a Suspense fallback for the browser to replace, onBrowserBailout receives two arguments:

  1. An Error describing the browser-only render. Its stack points to the use or abort call that consumed the value, and its cause is the reason supplied to browser.
  2. An errorInfo object containing the componentStack of the browser-only render.

The reason function can return any value. Returning a new Error gives the cause its own stack without creating that Error during rendering in the browser. React does not serialize the reason into the HTML or report the bailout to a client callback.

If browser-only rendering prevents the server shell from completing because there is no Suspense boundary, React reports the failure to the server renderer’s normal error handling callbacks instead of onBrowserBailout.


Aborting pending server rendering for the browser

You can pass the value returned by browser as the reason for aborting a server render. This leaves pending Suspense boundaries in their fallback state so React can render their content in the browser:

import {browser} from 'react-dom';
import {renderToPipeableStream} from 'react-dom/server';

const {pipe, abort} = renderToPipeableStream(<App />, {
onShellReady() {
pipe(response);
setTimeout(() => {
abort(browser('The server render timed out.'));
}, 10000);
}
});

Unlike aborting with an error, aborting with a value returned by browser is not reported to the server renderer’s onError callback or to hydrateRoot’s onRecoverableError callback. The server renderer reports each recovered Suspense boundary to onBrowserBailout instead.

Only abort with browser() after the server shell has completed. If the shell has not completed, there is no Suspense boundary that React can use to recover, so the server render will fail.

For server rendering APIs that accept an AbortSignal, pass browser() as the reason to AbortController.abort.