Skip to content

Commit f3b186f

Browse files
committed
Add browser-only examples gallery
1 parent dcde1e1 commit f3b186f

1 file changed

Lines changed: 140 additions & 1 deletion

File tree

src/content/reference/react-dom/browser.md

Lines changed: 140 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,10 +65,16 @@ During server rendering, `use(browser())` stops rendering the component and leav
6565
6666
### Rendering content only in the browser {/*rendering-content-only-in-the-browser*/}
6767
68-
Call `browser` inside `use` in a component that should only render in the browser:
68+
Call `browser` inside `use` in a component that should only render in the browser.
6969
7070
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.
7171
72+
<Recipes titleText="Examples of browser-only content">
73+
74+
#### Loading a saved draft {/*loading-a-saved-draft*/}
75+
76+
`localStorage` is only available in the browser. This example uses it to load and save a draft.
77+
7278
Press **Render the page** to see the loading fallback. React then displays a draft loaded from `localStorage`.
7379
7480
<Sandpack>
@@ -215,6 +221,139 @@ iframe {
215221
216222
</Sandpack>
217223
224+
<Solution />
225+
226+
#### Detecting the user's time zone {/*detecting-the-users-time-zone*/}
227+
228+
The browser can detect the user's time zone. This example waits for the browser before reading it.
229+
230+
Press **Render the page** to see the loading fallback. React then displays the time zone detected by the browser.
231+
232+
<Sandpack>
233+
234+
```js src/App.js active
235+
import { Suspense, use } from 'react';
236+
import { browser } from 'react-dom';
237+
238+
function TimeZone() {
239+
use(browser("The user's time zone is detected in the browser."));
240+
const timeZone = new Intl.DateTimeFormat().resolvedOptions().timeZone;
241+
return <p>Your time zone: {timeZone}</p>;
242+
}
243+
244+
export default function App() {
245+
return (
246+
<Suspense fallback={<p>Loading time zone...</p>}>
247+
<TimeZone />
248+
</Suspense>
249+
);
250+
}
251+
```
252+
253+
```js src/Document.js hidden
254+
import App from './App.js';
255+
256+
export default function Document() {
257+
return (
258+
<html lang="en">
259+
<head>
260+
<title>Time zone</title>
261+
</head>
262+
<body>
263+
<App />
264+
</body>
265+
</html>
266+
);
267+
}
268+
```
269+
270+
```js src/index.js hidden
271+
import { hydrateRoot } from 'react-dom/client';
272+
import { renderToReadableStream } from 'react-dom/server';
273+
import Document from './Document.js';
274+
import { flushReadableStreamToFrame } from './demo-helpers.js';
275+
import './styles.css';
276+
277+
async function main(frame) {
278+
const stream = await renderToReadableStream(<Document />);
279+
await flushReadableStreamToFrame(stream, frame);
280+
281+
// Wait so both the fallback and hydrated content are visible.
282+
await new Promise(resolve => setTimeout(resolve, 1200));
283+
hydrateRoot(frame.contentDocument, <Document />);
284+
}
285+
286+
const renderButton = document.getElementById('render');
287+
renderButton.addEventListener('click', () => {
288+
renderButton.disabled = true;
289+
main(document.getElementById('preview'));
290+
}, { once: true });
291+
```
292+
293+
```js src/demo-helpers.js hidden
294+
export async function flushReadableStreamToFrame(readable, frame) {
295+
const doc = frame.contentWindow.document;
296+
const decoder = new TextDecoder();
297+
const reader = readable.getReader();
298+
299+
while (true) {
300+
const {done, value} = await reader.read();
301+
if (done) {
302+
break;
303+
}
304+
doc.write(decoder.decode(value, {stream: true}));
305+
}
306+
307+
doc.write(decoder.decode());
308+
doc.close();
309+
}
310+
```
311+
312+
```html public/index.html hidden
313+
<!DOCTYPE html>
314+
<html lang="en">
315+
<head>
316+
<meta charset="UTF-8" />
317+
<title>Browser-only rendering</title>
318+
</head>
319+
<body>
320+
<button id="render">Render the page</button>
321+
<br /><br />
322+
<iframe id="preview" title="Rendered page"></iframe>
323+
</body>
324+
</html>
325+
```
326+
327+
```css src/styles.css hidden
328+
iframe {
329+
width: 100%;
330+
height: 80px;
331+
border: 0;
332+
}
333+
```
334+
335+
```json package.json hidden
336+
{
337+
"dependencies": {
338+
"react": "19.3.0-canary-eb8feb71-20260814",
339+
"react-dom": "19.3.0-canary-eb8feb71-20260814",
340+
"react-scripts": "latest"
341+
},
342+
"scripts": {
343+
"start": "react-scripts start",
344+
"build": "react-scripts build",
345+
"test": "react-scripts test --env=jsdom",
346+
"eject": "react-scripts eject"
347+
}
348+
}
349+
```
350+
351+
</Sandpack>
352+
353+
<Solution />
354+
355+
</Recipes>
356+
218357
<Note>
219358
220359
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:

0 commit comments

Comments
 (0)