hydrateRoot lets you display React components inside a browser DOM node whose HTML content was previously generated by react-dom/server.
The Hydration Process
Hydration is the process of attaching React to existing HTML:
- Server renders HTML - Users see content immediately
- JavaScript loads - React code downloads
- Hydration occurs - React attaches event listeners and takes over
tsximport { hydrateRoot } from 'react-dom/client'; import App from './App'; // The HTML was rendered on the server const domNode = document.getElementById('root'); const root = hydrateRoot(domNode, <App />);
Key Difference from createRoot
| Aspect | createRoot | hydrateRoot |
|---|---|---|
| Starting point | Empty DOM node | Pre-rendered HTML |
| Initial render | Creates all DOM | Attaches to existing DOM |
| Use case | Client-only apps | SSR/SSG apps |
Handling Hydration Mismatches
React expects the server HTML to match what it would render. Mismatches cause warnings:
tsx// Server rendered: <p>Hello, World</p> // Client renders: <p>Hello, User</p> // ⚠️ Hydration mismatch!
Suppressing Unavoidable Mismatches
For content that intentionally differs (like timestamps), use suppressHydrationWarning:
tsxfunction Timestamp() { return ( <time suppressHydrationWarning> {new Date().toLocaleString()} </time> ); }
Client-Only Content
For content that should only render on the client:
tsxfunction ClientOnly({ children }) { const [mounted, setMounted] = useState(false); useEffect(() => { setMounted(true); }, []); if (!mounted) return null; return children; } // Usage <ClientOnly> <BrowserOnlyWidget /> </ClientOnly>
Configuration Options
hydrateRoot accepts the same options as createRoot, plus:
tsxconst root = hydrateRoot(domNode, <App />, { onRecoverableError: (error) => { // Called when React recovers from hydration mismatches console.warn('Hydration mismatch recovered:', error); } });
Updating a Hydrated Root
After hydration, you can update the root like any other:
tsxconst root = hydrateRoot(domNode, <App />); // Later, update the app root.render(<App showModal={true} />);