Skip to content

Fix theme hydration warnings caused by mismatched server/client theme state #79

Description

@grantfox-oss

Description

Theme pages are currently emitting hydration warnings because the theme state differs between server render and client render. This is caused by an incomplete next-themes configuration in theme-provider.tsx, which allows the client to rehydrate with a different theme value than the server initially rendered.

This issue should stabilize theme initialization so the app renders the same theme on the server and client, and avoid a visible flash of theme change during hydration.


Tasks

  • Update theme-provider.tsx
  • Configure next-themes with:
    • defaultTheme
    • enableSystem
    • attribute="class"
    • disableTransitionOnChange or equivalent transition suppression
  • Ensure the provider uses a consistent initial theme value for both server and client
  • Apply the theme preference as early as possible on first client render
  • Verify the theme provider is wrapped around all theme pages and not rendered conditionally
  • If needed, add a safe mount guard or hydration-safe rendering pattern to keep theme DOM stable until the client theme is resolved

Implementation details

The provider should stop relying on implicit defaults and explicitly define the initial theme strategy. For example:

'use client'

import { ThemeProvider as NextThemesProvider } from 'next-themes'
import type { ThemeProviderProps } from 'next-themes/dist/types'

export function ThemeProvider({ children, ...props }: ThemeProviderProps) {
  return (
    <NextThemesProvider
      {...props}
      attribute="class"
      defaultTheme="system"
      enableSystem
      disableTransitionOnChange
    >
      {children}
    </NextThemesProvider>
  )
}

Key behavior to lock in

  • attribute="class" ensures theme is controlled via CSS class rather than inline styles
  • defaultTheme defines a stable initial server-side theme
  • enableSystem lets the browser preference apply consistently
  • disableTransitionOnChange prevents a flash when the theme switches after hydration
  • If defaultTheme="system" is used, the provider must still avoid theme mismatch flash by applying the preference in a hydration-safe way

Acceptance criteria

  • next-themes is explicitly configured with defaultTheme and enableSystem
  • Theme rendering is stable across server and client
  • No hydration warnings appear in the browser console on theme pages
  • The visible theme does not flash or jump during first render
  • Theme pages render the same initial theme class before and after hydration
  • The provider is implemented in theme-provider.tsx with a consistent theme initialization strategy

Why this matters

  • Hydration warnings indicate a mismatch between server-generated HTML and client-side React state
  • Theme mismatch can cause a visible flash and degrade perceived quality
  • A stable theme provider improves user experience and prevents inconsistent appearance across renders

Metadata

Metadata

Labels

GrantFox OSSIssue tracked in GrantFox OSSMaybe RewardedIssue may be eligible for a GrantFox rewardOfficial CampaignCampaign: Official CampaignbugSomething isn't working

Type

No type

Fields

No fields configured for issues without a type.

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions