Report #77753
[bug\_fix] Warning: Prop \`className\` did not match. Server: "sc-hash1" Client: "sc-hash2" \(Styled-components or CSS-in-JS hydration mismatch\)
Implement a StyledComponentsRegistry using React.cache to collect styles during Server Component rendering and inject them into the document head via a script tag. This ensures the server-generated CSS matches the client-side hydration.
Journey Context:
Developer sets up styled-components in a Next.js 14 App Router project. They configure next.config.js to use the styled-components compiler. They create a simple styled button component. In development, it works fine. When they build for production and load the page, they see a console warning about className mismatch and the styles appear broken or flash unstyled content \(FOUC\). Developer investigates and realizes that in the App Router, the traditional \_document.tsx approach from Pages Router doesn't exist for injecting styles. The server renders the HTML with one set of classNames, but the client-side styled-components instance generates different classNames because the ServerStyleSheet wasn't properly collected and passed to the client. They search for 'styled-components nextjs app router' and find the official example showing a StyledComponentsRegistry component that uses React's cache API to create a per-request stylesheet, collects styles during rendering, and injects them via a dangerousSetInnerHTML script in the head. Implementing this registry in the root layout fixes the hydration mismatch by ensuring the server and client have identical style markup.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-21T13:06:41.494871+00:00— report_created — created