Chakra UI Color Mode Persistence in SSR Builds: Choosing the Source of Truth
0 reputation · 05 Sept 2024, 02:15 UTC
0 reputation · 05 Sept 2024, 02:15 UTC
Chakra UI's color mode state has two possible sources of truth: the value persisted in localStorage on the client, and the theme's initialColorMode used when rendering on the server. In a client-only development setup the two never conflict, because no server markup exists. In a pre-rendered production build they can disagree, and React reports a hydration mismatch or briefly paints the fallback scheme.
The unresolved decision is which mechanism should own the initial value. Suppressing server rendering for the color mode provider keeps markup consistent but defers theme application; supplying the preference through a cookie or a server-side prop lets the first paint match, at the cost of making the response user-specific and complicating caching. Handling a missing or invalid stored value adds a further branch.
Assuming Chakra UI v2.x with a Next.js Pages Router setup, which approach is appropriate when the page is statically generated and no per-request cookie is available? Should the provider's server-rendered output be suppressed, or should the initial mode be resolved before the first render? And what should the fallback be when the stored preference is absent or unparseable?
29275 reputation · 05 Sept 2024, 06:50 UTC
When using Chakra UI v2.x with Next.js Pages Router and static generation (SSG), the client's localStorage must be the source of truth. Because the server cannot access client-side storage and you have no per-request cookies, any specific mode rendered on the server is a guess that will likely lead to a hydration mismatch or a visual flash (FOUC) when the client-side state takes over.
The most appropriate approach is to suppress the server-rendered output of the color mode state while using a blocking script to prevent the theme flash. This avoids the conflict between initialColorMode and localStorage by deferring the final theme application to the client, but doing so before the browser paints the body.
<head> of your _document.js. This script should read localStorage and manually apply the corresponding CSS class (e.g., chakra-ui-light or chakra-ui-dark) to the html or body element.ColorModeProvider to use the theme's initialColorMode as the baseline, but rely on the blocking script to override it immediately upon page load.suppressHydrationWarning on the html element to prevent React from complaining about the attribute difference between the server-generated HTML and the script-modified DOM.When the stored value is absent or unparseable, the fallback logic should follow this priority chain:
window.matchMedia('(prefers-color-scheme: dark)').matches. This ensures the first-time user experience matches their OS settings.initialColorMode defined in your Chakra theme configuration.To verify the implementation is working without causing a flash:
localStorage and verify the page loads using the system preference or initialColorMode.Note: This recommendation assumes you are not using a Middleware layer to inject cookies; if you introduce a cookie-based system, the source of truth shifts to the server.
Use comments to ask for clarification. Post a solution as an answer.
No question comments on this page.