From 7c373c8e0a080783722e94483d2eab59d463c6ae Mon Sep 17 00:00:00 2001 From: Arnas Donauskas Date: Fri, 5 Jun 2026 13:46:23 +0300 Subject: [PATCH] fix(theme): suppress hydration warning on root html data-theme (#207) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The `theme-boot` beforeInteractive script in layout.tsx rewrites `data-theme` on from localStorage before React hydrates, so for any non-default theme the client DOM intentionally differs from the server-rendered DEFAULT_THEME ("violet"). React then logged a hydration mismatch on on every load where the saved theme differed. Add suppressHydrationWarning to the root . It's scoped to that element's own attributes (child mismatches still surface) and preserves the documented localStorage-only/device-scoped theme design — unlike a cookie-based SSR approach, which would change that behavior. Verified in-browser (Next 16.2.6 / Turbopack): with a non-default theme in localStorage, the reproduced "+ data-theme=violet / - data-theme=cobalt" hydration error is gone; removing the prop brings it back (negative control). typecheck, lint (0 errors), 370 tests pass. Co-Authored-By: Claude Opus 4.8 (1M context) --- src/app/layout.tsx | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 0956aa5..39ffbc3 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -70,6 +70,13 @@ export default function RootLayout({ lang="en" data-theme={DEFAULT_THEME} className={`${inter.variable} h-full antialiased`} + // The `theme-boot` script below rewrites `data-theme` on + // from localStorage before React hydrates, so for any non-default + // theme the client DOM intentionally differs from the server- + // rendered `DEFAULT_THEME`. suppressHydrationWarning silences the + // expected mismatch — it only applies to this element's own + // attributes, so genuine mismatches in children still surface. + suppressHydrationWarning >