Fix: Hydration failed because the initial UI does not match
The Symptom
You are building a React application using a Server-Side Rendering (SSR) framework like Next.js or Remix. Upon loading the page in the browser, the console throws a massive red error, and the UI might briefly flash or break entirely.
Error: Hydration failed because the initial UI does not match what was rendered on the server.
Warning: Expected server HTML to contain a matching <div> in <div>.
The Cure
React requires the HTML generated on the server to be a pixel-perfect match to the HTML rendered on the client's first pass. To fix this, use a useMounted custom hook to delay the rendering of client-specific data (like dates, random numbers, or localStorage data) until after the initial hydration cycle completes.
Immediate Resolution (React / Next.js):
import { useState, useEffect } from 'react';
// 1. Create a reusable hook
export function useMounted() {
const [isMounted, setIsMounted] = useState(false);
useEffect(() => {
setIsMounted(true);
}, []);
return isMounted;
}
// 2. Use the hook in your component
export default function UserDashboard() {
const isMounted = useMounted();
// 3. Return a generic server-safe skeleton until mounted
if (!isMounted) {
return <div>Loading user preferences...</div>; // Matches server HTML exactly
}
// 4. Safe to render client-side specifics (window, localStorage, dynamic dates)
const theme = window.localStorage.getItem('theme') || 'dark';
return (
<div className={theme}>
Your local time is: {new Date().toLocaleTimeString()}
</div>
);
}
The Breakdown: Why does this happen?
In modern web development, "Hydration" is the process where React attaches event listeners to the static HTML that was generated by the server. React 18+ is extremely strict: if the DOM structure or text content returned by the server is even slightly different from what the client browser expects on its first render pass, React panics.
Common culprits that cause a mismatch:
- Dynamic Dates/Times: The server generates a timestamp (e.g., `12:00:01 PM`), but by the time the browser renders, a second has passed (`12:00:02 PM`).
- Client-Only Data: Using `window.innerWidth` or `localStorage` to conditionally render a sidebar. The server has no concept of a "window," so it assumes the sidebar is hidden. The browser reads the window width and tries to render it immediately.
Prevention & Best Practices
Aside from the useMounted hook, ensure you are writing valid HTML. React's hydration engine will violently fail if your HTML tags are improperly nested, even if the data is static.
-
Never nest blocks inside inline elements: Placing a
<div>inside a<p>tag will cause the browser to automatically "correct" the HTML by closing the<p>tag early, instantly breaking React's hydration tree. -
Use
suppressHydrationWarning: If you absolutely must render a timestamp that will inevitably mismatch, you can add<time suppressHydrationWarning>{date}</time>. Note: This only works for text content, not structural mismatches.
Loading logs...