browser
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.
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 bybrowser, so the browser does not unnecessarily create the error or capture its stack. The server renderer attaches the resulting value as thecauseof theErrorpassed toonBrowserBailout.
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
browseris not available in areact-serverenvironment. 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
browsertouseduring 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 touseduring 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
browsertouse. Do not throw the value directly.
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.
Conditionally rendering in the browser
Like other calls to use, use(browser()) can be called conditionally, including inside a custom Hook. For example, you can wrap a data-fetching library’s useQuery to render initial data on the server, but defer to the browser when that data is missing:
function useBrowserQuery(query, options) {
if (options.initialData === undefined) {
use(browser('No initial data was provided for this query.'));
}
return useQuery(query, options);
}
function ProductDetails({productId, initialData}) {
const product = useBrowserQuery(['product', productId], {
initialData,
});
return <h1>{product.name}</h1>;
}On the server, useBrowserQuery calls the underlying useQuery only when initialData is available. Otherwise, use(browser()) leaves the nearest Suspense fallback in the HTML. In the browser, use(browser()) continues immediately, so the query library can fetch the data or read it from its client cache.
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:
- An
Errordescribing the browser-only render. Its stack points to theuseor abort call that consumed the value, and itscauseis the reason supplied tobrowser. - An
errorInfoobject containing thecomponentStackof 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.