Skip to content

fix(react): resolve theme toggle hydration mismatch - #1103

Open
puneetnith28 wants to merge 3 commits into
nodejs:mainfrom
puneetnith28:fix/theme-toggle-hydration
Open

puneetnith28 wants to merge 3 commits into
nodejs:mainfrom
puneetnith28:fix/theme-toggle-hydration

Conversation

@puneetnith28

Copy link
Copy Markdown

Description

Fixes a hydration mismatch where the ThemeToggle icon resets to the system icon after page reload when a user preference (dark / light) is stored.

Changes

  • Initialized pref state to 'system' by default in useTheme.mjs to ensure server HTML and client initial render match.
  • Synchronized pref with localStorage inside a useEffect hook on client mount.
  • Added key={themePreference} to <ThemeToggle> to ensure clean remounting when the theme preference is applied.

References

@puneetnith28
puneetnith28 requested a review from a team as a code owner September 15, 2026 21:18
@vercel

vercel Bot commented Sep 15, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated
api-docs-tooling Ready Ready Preview Sep 16, 2026 10:49am UTC

Request Review

@puneetnith28

Copy link
Copy Markdown
Author

Please review this PR and let me know if any further changes are needed.
Thanks!!

Comment on lines +34 to +39
useEffect(() => {
const stored = localStorage.getItem('theme');
if (stored) {
setPref(stored);
}
}, []);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
useEffect(() => {
const stored = localStorage.getItem('theme');
if (stored) {
setPref(stored);
}
}, []);
useEffect(() => {
const stored = localStorage.getItem('theme');
if (stored === 'light' || stored === 'dark') {
setPref(stored);
}
}, []);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we dont need to reapply system

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

wouldn’t stored !== pref be a little more robust?

@TusharThakur04 TusharThakur04 Sep 15, 2026

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

if somehow stored is returned as null, its better to check explicitly. WDYT?

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated to explicitly check for 'light' or 'dark' to safely handle null and avoid re-applying system.
Thanks for suggestion !!

<ThemeToggle
onChange={setThemePreference}
currentTheme={themePreference}
key={themePreference}

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why we need key here? without this , it seems to fix the icon just the same

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I added key thinking a remount might be needed, but currentTheme prop updates already handle the re-render properly

@puneetnith28
puneetnith28 requested a review from ryzrr September 16, 2026 11:03
@ryzrr

ryzrr commented Sep 16, 2026

Copy link
Copy Markdown
Contributor

LGTM !

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants