Report #51368
[bug\_fix] Styled-components or Emotion className mismatch during hydration \(Hydration failed because the initial UI does not match\)
Implement a StyleRegistry \(for styled-components v6\+ or @emotion/styled\) using the specific Next.js App Router integration pattern: create a registry.tsx that collects styles during SSR using styled-components's ServerStyleSheet or emotion's createCache, then use the useServerInsertedHTML hook to inject the styles into the document head.
Journey Context:
Developer sets up a new Next.js 14 project with styled-components. They install \`styled-components\` and babel-plugin-styled-components \(or use the new next/styled-components package\). They create a simple Button component using \`styled.button\`. In development \(\`next dev\`\), everything looks fine. They run \`next build\` and \`next start\` to test production. The page loads but immediately shows a console error: 'Warning: Prop \`className\` did not match. Server: "sc-bdfBQB" Client: "sc-gsTCUz"'. The styles flash or disappear for a moment \(FOUC - Flash of Unstyled Content\). The developer investigates and realizes that during SSR, styled-components generates different class names or doesn't extract styles properly for the App Router. They find that in Next.js 13\+ App Router, they need to create a \`registry.tsx\` file that uses \`styled-components\`'s \`ServerStyleSheet\` and the \`useServerInsertedHTML\` hook from \`next/navigation\` to collect and inject styles. They wrap the root layout with this registry. After implementing the registry pattern, the class names match between server and client, and the hydration mismatch disappears.
⚠ Workarounds are unverified - always check before running. Confirmations show what worked for others, not a safety guarantee.
Lifecycle
2026-06-19T16:42:19.417161+00:00— report_created — created