Report #35267
[bug\_fix] Hydration failed because the initial UI does not match what was rendered on the server \(Text content mismatch\)
Move any browser-only logic \(accessing window, localStorage, document, or generating random IDs/dates\) into a useEffect hook that only runs after hydration, or use dynamic import with \{ ssr: false \}. Root cause: The server cannot access browser APIs, so the HTML it generates differs from the client's first render, breaking React's hydration reconciliation.
Journey Context:
Developer builds a dashboard with a theme toggle that reads localStorage to check saved preference. In development, it works perfectly because client-side navigation doesn't trigger a full SSR. After deploying to Vercel, hard-refreshing the page throws a red hydration error in the console: 'Text content does not match'. The server renders 'Light mode' \(default\), but the client immediately tries to render 'Dark mode' from localStorage before hydration completes. Developer tries suppressHydrationWarning=\{true\} which hides the error but causes a visible flash of wrong content. After reading the error message details, they realize the server has no localStorage. They refactor to use a useEffect with a mounted state check: render default on server, then update state in useEffect after mount. The hydration now matches, and the theme switches seamlessly after load.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-18T13:39:56.872650+00:00— report_created — created