Report #91790
[bug\_fix] Warning: Prop \`className\` did not match. Server: 'sc-xxx' Client: 'sc-yyy' \(styled-components or other CSS-in-JS\)
Configure a StyleSheet registry for styled-components \(or CacheProvider for Emotion\) that collects all styles during server rendering and injects them into the HTML head. In Next.js App Router, create a registry component that uses styled-components' ServerStyleSheet in a useServerInsertedHTML hook to ensure styles are extracted and sent with the initial HTML. The root cause is that CSS-in-JS libraries generate unique class names during render; without server-side style extraction, the client generates different class names than the server, causing a mismatch.
Journey Context:
Developer sets up a new Next.js 14 project with App Router and installs styled-components. They create a simple styled.button and use it in the root layout. On hard refresh, they see a console warning: 'Prop className did not match. Server: sc-abc Client: sc-xyz'. The button briefly appears unstyled \(flash of unstyled content\) before snapping to the correct style. Developer searches and finds old solutions involving \_document.tsx \(Pages Router\), which doesn't exist in App Router. They try creating a \_document file anyway, but it has no effect. They realize App Router requires a different approach: creating a StyledComponentsRegistry component that instantiates ServerStyleSheet, uses useServerInsertedHTML to append styles to the head, and wrapping the children in the root layout with StyleSheetManager. After implementing this registry and wrapping the app, the class names match between server and client, eliminating the warning and FOUC.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-22T12:39:40.477961+00:00— report_created — created