From 9e97ad0bbc38800041ce908250fe0128a2d437b1 Mon Sep 17 00:00:00 2001 From: Aristos Markogiannakis Date: Thu, 30 Jul 2026 07:19:17 +0100 Subject: [PATCH 01/11] Add upcoming conferences for React and CityJS (#8438) Please accept my changes for React Alicante and CityJS Athens --- src/content/community/conferences.md | 34 ++++++++++++++++++++-------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/src/content/community/conferences.md b/src/content/community/conferences.md index 2e95e24ea..f3ae269bb 100644 --- a/src/content/community/conferences.md +++ b/src/content/community/conferences.md @@ -10,27 +10,41 @@ Do you know of a local React.js conference? Add it here! (Please keep the list c ## Upcoming Conferences {/*upcoming-conferences*/} -### React Paris 2026 {/*react-paris-2026*/} -March 26 - 27, 2026. In-person in Paris, France (hybrid event) +### ZurichJS Conf 2026 {/*zurichjs-conf-2026*/} +September 10-11, 2026. In-person in Zurich, Switzerland -[Website](https://react.paris/) - [Twitter](https://x.com/BeJS_) +[Website](https://conf.zurichjs.com?utm_campaign=ZurichJS_Conf&utm_source=referral&utm_content=reactjs_community_conferences) - [Twitter](https://x.com/zurichjs) - [LinkedIn](https://www.linkedin.com/company/zurichjs/) -### CityJS London 2026 {/*cityjs-london-2026*/} -April 14-17, 2026. In-person in London +### React Alicante 2026 {/*react-alicante-2026*/} +Sep 24 - 26, 2026. In-person in Alicante -[Website](https://india.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social) +[Website](https://reactalicante.es//) - [Twitter](https://x.com/ReactAlicante) -### ZurichJS Conf 2026 {/*zurichjs-conf-2026*/} -September 10-11, 2026. In-person in Zurich, Switzerland +### CityJS Athens 2026 {/*cityjs-athens-2026*/} +October 21-23, 2026. In-person in Athens + +[Website](https://athens.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social) + + +## Past Conferences {/*past-conferences*/} -[Website](https://conf.zurichjs.com?utm_campaign=ZurichJS_Conf&utm_source=referral&utm_content=reactjs_community_conferences) - [Twitter](https://x.com/zurichjs) - [LinkedIn](https://www.linkedin.com/company/zurichjs/) ### React Conf Japan 2027 {/*react-conf-japan-2027*/} April 24, 2027. In-person in Tokyo, Japan [Website](https://reactconf.jp/) - [Twitter](https://x.com/reactconfjp) -## Past Conferences {/*past-conferences*/} +### CityJS London 2026 {/*cityjs-london-2026*/} +April 14-17, 2026. In-person in London + +[Website](https://india.cityjsconf.org/) - [Twitter](https://x.com/cityjsconf) - [Bluesky](https://bsky.app/profile/cityjsconf.bsky.social) + + +### React Paris 2026 {/*react-paris-2026*/} +March 26 - 27, 2026. In-person in Paris, France (hybrid event) + +[Website](https://react.paris/) - [Twitter](https://x.com/BeJS_) + ### CityJS New Delhi 2026 {/*cityjs-newdelhi-2026*/} February 12-13, 2026. In-person in New Delhi, India From c7d6b700038c63d1aaf2c649af1aefe01ebbacac Mon Sep 17 00:00:00 2001 From: Ruslan Lesiutin <28902667+hoxyq@users.noreply.github.com> Date: Fri, 31 Jul 2026 13:38:41 +0100 Subject: [PATCH 02/11] Add conditional use warning deeplink (#8567) --- src/content/reference/react/use.md | 2 +- vercel.json | 5 +++++ 2 files changed, 6 insertions(+), 1 deletion(-) diff --git a/src/content/reference/react/use.md b/src/content/reference/react/use.md index 7388efa1c..a51873265 100644 --- a/src/content/reference/react/use.md +++ b/src/content/reference/react/use.md @@ -662,7 +662,7 @@ This cache pattern is the foundation for [re-fetching data](#re-fetching-data-in -Don't skip calling `use` based on whether a Promise is already settled. +##### Don't skip calling `use` based on whether a Promise is already settled. {/*conditional-use*/} Unlike other hooks, `use` can be called inside conditions and loops — but it must always be called for the Promise itself. Never read `promise.status` or `promise.value` directly to bypass `use`; always pass the Promise to `use` and let React handle it. diff --git a/vercel.json b/vercel.json index 87d006def..2aa3316c5 100644 --- a/vercel.json +++ b/vercel.json @@ -174,6 +174,11 @@ "destination": "/warnings/invalid-hook-call-warning#mismatching-versions-of-react-and-react-dom", "permanent": false }, + { + "source": "/warnings/conditional-use-of-use", + "destination": "/reference/react/use#conditional-use", + "permanent": false + }, { "source": "/reference/react/directives", "destination": "/reference/rsc/directives", From 47a40802effbc143e2019810c251fd097b3fd5a0 Mon Sep 17 00:00:00 2001 From: Alex Hunt Date: Mon, 10 Aug 2026 18:41:43 +0100 Subject: [PATCH 03/11] Add/fix RN team member links (#8558) --- .../images/team/{gh-rh389.jpg => gh-robhogan.jpg} | Bin src/content/community/team.md | 10 +++++----- 2 files changed, 5 insertions(+), 5 deletions(-) rename public/images/team/{gh-rh389.jpg => gh-robhogan.jpg} (100%) diff --git a/public/images/team/gh-rh389.jpg b/public/images/team/gh-robhogan.jpg similarity index 100% rename from public/images/team/gh-rh389.jpg rename to public/images/team/gh-robhogan.jpg diff --git a/src/content/community/team.md b/src/content/community/team.md index e321f240b..dd77a539e 100644 --- a/src/content/community/team.md +++ b/src/content/community/team.md @@ -26,7 +26,7 @@ React work is organized into working groups, each responsible for an area of the - + Ricky majored in theoretical math and somehow found himself on the React Native team for a couple years before joining the React team. When he's not programming you can find him snowboarding, biking, climbing, golfing, or closing GitHub issues that do not match the issue template. @@ -38,7 +38,7 @@ React work is organized into working groups, each responsible for an area of the ## Working Group members {/*working-group-members*/} - + @@ -82,11 +82,11 @@ React work is organized into working groups, each responsible for an area of the - + - + - + Ruslan's introduction to UI programming started when he was a kid by manually editing HTML templates for his custom gaming forums. Somehow, he ended up majoring in Computer Science. He enjoys music, games, and memes. Mostly memes. From 383a1e9239c8c084a16a19daa4fc2a7ad04e2a3a Mon Sep 17 00:00:00 2001 From: Aurora Scharff <66901228+aurorascharff@users.noreply.github.com> Date: Wed, 12 Aug 2026 15:21:35 +0200 Subject: [PATCH 04/11] Clarify Suspense link in useDeferredValue docs (#8591) --- src/content/reference/react/useDeferredValue.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/content/reference/react/useDeferredValue.md b/src/content/reference/react/useDeferredValue.md index 1f85dcb23..f5aa29bb1 100644 --- a/src/content/reference/react/useDeferredValue.md +++ b/src/content/reference/react/useDeferredValue.md @@ -88,7 +88,7 @@ During updates, the deferred value will "lag behin This example assumes you use a data source that [activates a Suspense boundary](/reference/react/Suspense#what-activates-a-suspense-boundary), such as a Promise you read with [`use`](/reference/react/use). -[Learn more about Suspense and its limitations.](/reference/react/Suspense) +[Learn more about Suspense.](/reference/react/Suspense) From 7a32c8a67af39eca0391fcb1ed9063577bc2b2a8 Mon Sep 17 00:00:00 2001 From: Laxmana Megalamani Date: Tue, 18 Aug 2026 01:07:53 +0530 Subject: [PATCH 05/11] Fix YouTube video overflow on mobile (#8609) --- src/content/versions.md | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/content/versions.md b/src/content/versions.md index 2c2e3620b..87c68115d 100644 --- a/src/content/versions.md +++ b/src/content/versions.md @@ -325,4 +325,7 @@ See the first blog post: [Why did we build React?](https://legacy.reactjs.org/bl React was open sourced at Facebook Seattle in 2013: - + From e730fd0dd71f3b26a9988cc5c1774dc7a39fa486 Mon Sep 17 00:00:00 2001 From: Nasser Date: Tue, 18 Aug 2026 21:45:59 +0200 Subject: [PATCH 06/11] Add cache, cacheSignal, and captureOwnerStack to the APIs overview (#8597) --- src/content/reference/react/apis.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/content/reference/react/apis.md b/src/content/reference/react/apis.md index 777b8fc7b..51438ad9b 100644 --- a/src/content/reference/react/apis.md +++ b/src/content/reference/react/apis.md @@ -15,6 +15,9 @@ In addition to [Hooks](/reference/react/hooks) and [Components](/reference/react * [`memo`](/reference/react/memo) lets your component skip re-renders with same props. Used with [`useMemo`](/reference/react/useMemo) and [`useCallback`.](/reference/react/useCallback) * [`startTransition`](/reference/react/startTransition) lets you mark a state update as non-urgent. Similar to [`useTransition`.](/reference/react/useTransition) * [`act`](/reference/react/act) lets you wrap renders and interactions in tests to ensure updates have processed before making assertions. +* [`cache`](/reference/react/cache) lets you cache the result of a data fetch or computation. +* [`cacheSignal`](/reference/react/cacheSignal) lets you know when the `cache()` lifetime is over. +* [`captureOwnerStack`](/reference/react/captureOwnerStack) reads the current Owner Stack in development and returns it as a string if available. --- From 96ad418a9a8f00fb63e7d6c56400384b37539138 Mon Sep 17 00:00:00 2001 From: Josh Story Date: Wed, 19 Aug 2026 11:12:12 -0700 Subject: [PATCH 07/11] Document browser-only rendering (#8582) * Document browser-only rendering Add the Canary browser API reference, including optional lazy reasons, server bailout reporting, fatal and abort behavior, navigation entries, and onBrowserBailout options for every streaming, resume, and prerender API that supports it. * Polish browser API docs and add live example * Document browser with use and Suspense --------- Co-authored-by: Aurora Scharff --- src/content/reference/react-dom/browser.md | 293 ++++++++++++++++++ src/content/reference/react-dom/index.md | 6 + .../server/renderToPipeableStream.md | 1 + .../server/renderToReadableStream.md | 1 + .../reference/react-dom/server/resume.md | 1 + .../server/resumeToPipeableStream.md | 1 + .../reference/react-dom/static/prerender.md | 1 + .../react-dom/static/prerenderToNodeStream.md | 1 + .../react-dom/static/resumeAndPrerender.md | 1 + .../static/resumeAndPrerenderToNodeStream.md | 1 + src/content/reference/react/Suspense.md | 123 ++++++++ src/content/reference/react/use.md | 156 ++++++++++ src/sidebarReference.json | 5 + 13 files changed, 591 insertions(+) create mode 100644 src/content/reference/react-dom/browser.md diff --git a/src/content/reference/react-dom/browser.md b/src/content/reference/react-dom/browser.md new file mode 100644 index 000000000..11f787d2c --- /dev/null +++ b/src/content/reference/react-dom/browser.md @@ -0,0 +1,293 @@ +--- +title: browser +version: canary +--- + + + + + +**The `browser` API is currently only available in React’s Canary and Experimental channels.** + +[Learn more about React’s release channels here.](/community/versioning-policy#all-release-channels) + + + +`browser` lets you mark a component as browser-only during server rendering. + +```js +use(browser(reason?)) +``` + + + + + +--- + +## Reference {/*reference*/} + +### `browser(reason?)` {/*browser*/} + +Call `browser` inside [`use`](/reference/react/use) to mark a component as browser-only during server rendering: + +```js +import { use } from 'react'; +import { browser } from 'react-dom'; + +function BrowserOnly() { + use(browser('This component requires browser APIs.')); + return ; +} +``` + +During server rendering, `use(browser())` stops rendering the component and leaves the closest [``](/reference/react/Suspense) boundary's fallback in its place. In the browser, `use(browser())` returns `undefined`, so the component renders normally. + +[See more examples below.](#usage) + +#### Parameters {/*parameters*/} + +* **optional** `reason`: A string or function that explains why the content needs to render in the browser. The string or the function's return value becomes the `cause` of the `Error` passed to [`onBrowserBailout`](#reporting-browser-only-rendering-on-the-server). React calls a reason function each time a server renderer encounters the value returned by `browser`, but does not call it in the browser. If creating the reason is expensive, pass a function such as `() => new Error(...)`. + +#### Returns {/*returns*/} + +`browser` returns a value that you can pass to `use` in a component or use as the reason when [aborting a server render](#aborting-pending-server-rendering-for-the-browser). In the browser, passing this value to `use` returns `undefined`. + +#### Caveats {/*caveats*/} + +* `use(browser())` must be inside a `` boundary during server rendering. Without one, the server render fails. +* In a React Server Components app, `use(browser())` must be called from a [Client Component](/reference/rsc/use-client), not a [Server Component](/reference/rsc/server-components). +* Calling `browser()` by itself has no effect. To mark a component as browser-only, pass the value returned by `browser` to `use`. Do not throw it. + +--- + +## Usage {/*usage*/} + +### Rendering content only in the browser {/*rendering-content-only-in-the-browser*/} + +Call `browser` inside `use` in a component that should only render in the browser: + +You can use this instead of checking `typeof window`, waiting for an [`Effect`](/reference/react/useEffect) to set mounted state, or using a framework option to disable server rendering. + +Press **Render the page**. The loading fallback appears first. After a short delay, React hydrates the page and displays the browser-only editor. + + + +```js src/App.js active +import { Suspense, use } from 'react'; +import { browser } from 'react-dom'; + +function BrowserOnlyEditor() { + use(browser('The editor requires browser APIs.')); + return ; +} + +export default function App() { + return ( + Loading editor...

}> + +
+ ); +} +``` + +```js src/Document.js hidden +import App from './App.js'; + +export default function Document() { + return ( + + + Article editor + + +

Article editor

+ + + + ); +} +``` + +```js src/index.js +import { hydrateRoot } from 'react-dom/client'; +import { renderToReadableStream } from 'react-dom/server'; +import Document from './Document.js'; +import { flushReadableStreamToFrame } from './demo-helpers.js'; +import './styles.css'; + +async function main(frame) { + const stream = await renderToReadableStream(); + await flushReadableStreamToFrame(stream, frame); + + // Wait so both the fallback and hydrated content are visible. + await new Promise(resolve => setTimeout(resolve, 1200)); + hydrateRoot(frame.contentDocument, ); +} + +const renderButton = document.getElementById('render'); +renderButton.addEventListener('click', () => { + renderButton.disabled = true; + main(document.getElementById('preview')); +}, { once: true }); +``` + +```js src/demo-helpers.js hidden +export async function flushReadableStreamToFrame(readable, frame) { + const doc = frame.contentWindow.document; + const decoder = new TextDecoder(); + for await (const chunk of readable) { + doc.write(decoder.decode(chunk, { stream: true })); + } + doc.close(); +} +``` + +```html public/index.html + + + + + Browser-only rendering + + + +

+ + + +``` + +```css src/styles.css hidden +iframe { + width: 100%; + height: 180px; + border: 1px solid #aaa; +} +``` + +```json package.json hidden +{ + "dependencies": { + "react": "canary", + "react-dom": "canary", + "react-scripts": "latest" + }, + "scripts": { + "start": "react-scripts start", + "build": "react-scripts build", + "test": "react-scripts test --env=jsdom", + "eject": "react-scripts eject" + } +} +``` + +
+ + + +In a React Server Components app, `use(browser())` must be called from a Client Component. If your framework uses Server Components by default, add the [`'use client'`](/reference/rsc/use-client) directive to that file or move the call to a child Client Component: + +```js {1} +'use client'; + +import { use } from 'react'; +import { browser } from 'react-dom'; + +export default function BrowserOnlyEditor() { + use(browser('The editor requires browser APIs.')); + return ; +} +``` + + + +--- + +### Conditionally rendering in the browser {/*conditionally-rendering-in-the-browser*/} + +Like other calls to [`use`](/reference/react/use), you can call `use(browser())` conditionally or inside a custom Hook. For example, you can wrap a Suspense-enabled data-fetching library's `useQuery` and skip server rendering when initial data is missing: + +```js {3} +function useBrowserQuery(query, options) { + if (options.initialData === undefined) { + use(browser('useBrowserQuery: No initial data was provided.')); + } + + return useQuery(query, options); +} + +function ProductDetails({ productId, initialData }) { + const product = useBrowserQuery(`/api/products/${productId}`, { + initialData, + }); + + return

{product.name}

; +} +``` + +On the server, `useBrowserQuery` calls `useQuery` only when `initialData` is available. Otherwise, the closest Suspense boundary's fallback remains in the HTML. In the browser, `use(browser())` returns `undefined`, so the query library can fetch the data or read it from its client cache. + +--- + +### Reporting browser-only rendering on the server {/*reporting-browser-only-rendering-on-the-server*/} + +Pass an `onBrowserBailout` callback to the server renderer to report browser-only rendering. When React leaves a Suspense fallback for the browser, it does not call the server renderer's `onError` callback or [`hydrateRoot`'s `onRecoverableError`](/reference/react-dom/client/hydrateRoot#error-logging-in-production) callback. This example also passes a reason, which is available as the reported error's `cause`: + +```js +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 ; +} + +const { pipe } = renderToPipeableStream( + Loading editor...

}> + +
, + { + onShellReady() { + pipe(response); + }, + onBrowserBailout(error, errorInfo) { + logBrowserBailout(error, errorInfo); + } + } +); +``` + +`onBrowserBailout` receives two arguments: + +1. An `Error` describing the browser-only render. If you passed a reason to `browser`, it is available as the error's `cause`. +2. An `errorInfo` object with a `componentStack` showing where browser-only rendering occurred. + +The reason function can return any value. Return a new `Error` to give the cause its own stack without creating the `Error` in the browser. React does not serialize the reason into the HTML. + +If there is no Suspense boundary to provide a fallback, the server render fails. React reports the failure through the renderer's usual error callbacks instead of `onBrowserBailout`. + +--- + +### Aborting pending server rendering for the browser {/*aborting-pending-server-rendering-for-the-browser*/} + +If you call a server rendering API directly, you can stop waiting for pending content and let the browser finish rendering it. Pass the value returned by `browser` as the reason when aborting the server render. React then leaves pending Suspense boundaries in their fallback state and renders their content in the browser: + +```js {1,8} +import { browser } from 'react-dom'; +import { renderToPipeableStream } from 'react-dom/server'; + +const { pipe, abort } = renderToPipeableStream(, { + onShellReady() { + pipe(response); + setTimeout(() => { + abort(browser('The server render timed out.')); + }, 10000); + } +}); +``` + +A `browser` abort reason does not trigger the server renderer's `onError` callback or `hydrateRoot`'s `onRecoverableError` callback. Instead, the server renderer reports each recovered Suspense boundary to `onBrowserBailout`. + +For server rendering APIs that accept an [`AbortSignal`](https://developer.mozilla.org/en-US/docs/Web/API/AbortSignal), pass `browser()` as the reason to [`AbortController.abort`](https://developer.mozilla.org/en-US/docs/Web/API/AbortController/abort). diff --git a/src/content/reference/react-dom/index.md b/src/content/reference/react-dom/index.md index d01bd6562..6f1188442 100644 --- a/src/content/reference/react-dom/index.md +++ b/src/content/reference/react-dom/index.md @@ -30,6 +30,12 @@ These APIs can be used to make apps faster by pre-loading resources such as scri * [`preinit`](/reference/react-dom/preinit) lets you fetch and evaluate an external script or fetch and insert a stylesheet. * [`preinitModule`](/reference/react-dom/preinitModule) lets you fetch and evaluate an ESM module. +## Server Rendering APIs {/*server-rendering-apis*/} + +This API controls how components render on the server: + +* [`browser`](/reference/react-dom/browser) lets you mark a component as browser-only during server rendering. + --- ## Entry points {/*entry-points*/} diff --git a/src/content/reference/react-dom/server/renderToPipeableStream.md b/src/content/reference/react-dom/server/renderToPipeableStream.md index 9668e01b9..5d48c6a66 100644 --- a/src/content/reference/react-dom/server/renderToPipeableStream.md +++ b/src/content/reference/react-dom/server/renderToPipeableStream.md @@ -56,6 +56,7 @@ On the client, call [`hydrateRoot`](/reference/react-dom/client/hydrateRoot) to * **optional** `namespaceURI`: A string with the root [namespace URI](https://developer.mozilla.org/en-US/docs/Web/API/Document/createElementNS#important_namespace_uris) for the stream. Defaults to regular HTML. Pass `'http://www.w3.org/2000/svg'` for SVG or `'http://www.w3.org/1998/Math/MathML'` for MathML. * **optional** `nonce`: A [`nonce`](http://developer.mozilla.org/en-US/docs/Web/HTML/Element/script#nonce) string to allow scripts for [`script-src` Content-Security-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Content-Security-Policy/script-src). * **optional** `onAllReady`: A callback that fires when all rendering is complete, including both the [shell](#specifying-what-goes-into-the-shell) and all additional [content.](#streaming-more-content-as-it-loads) You can use this instead of `onShellReady` [for crawlers and static generation.](#waiting-for-all-content-to-load-for-crawlers-and-static-generation) If you start streaming here, you won't get any progressive loading. The stream will contain the final HTML. + * **optional** `onBrowserBailout`: A callback React calls when it recovers from [`browser()`](/reference/react-dom/browser) by leaving a Suspense fallback for the browser to replace. It receives an `Error` describing the browser-only render and an `errorInfo` object containing the `componentStack`. If a reason was passed to `browser`, it is available as `error.cause`. By default, React does nothing. [See how to report browser-only rendering.](/reference/react-dom/browser#reporting-browser-only-rendering-on-the-server) * **optional** `onError`: A callback that fires whenever there is a server error, whether [recoverable](#recovering-from-errors-outside-the-shell) or [not.](#recovering-from-errors-inside-the-shell) By default, this only calls `console.error`. If you override it to [log crash reports,](#logging-crashes-on-the-server) make sure that you still call `console.error`. You can also use it to [adjust the status code](#setting-the-status-code) before the shell is emitted. * **optional** `onShellReady`: A callback that fires right after the [initial shell](#specifying-what-goes-into-the-shell) has been rendered. You can [set the status code](#setting-the-status-code) and call `pipe` here to start streaming. React will [stream the additional content](#streaming-more-content-as-it-loads) after the shell along with the inline `