Skip to content

Commit 0780973

Browse files
committed
🤖 fix: ThemeProvider should not use forcedTheme as persistence default
Changed ThemeProvider to use resolveSystemTheme() as the default for usePersistedState instead of forcedTheme. This prevents the issue where usePersistedState would check localStorage first and ignore the default. Now: - persistedTheme uses system preference as default - activeTheme = forcedTheme ?? persistedTheme (forcedTheme takes precedence) - When Chromatic sets forcedTheme='light', it overrides persistence - When forcedTheme is undefined (local dev), uses persistence/system This ensures light mode stories render in light theme and dark mode stories render in dark theme during Chromatic snapshots.
1 parent bbf3bff commit 0780973

File tree

1 file changed

+11
-9
lines changed

1 file changed

+11
-9
lines changed

src/browser/contexts/ThemeContext.tsx

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,17 +52,19 @@ function applyThemeToDocument(theme: ThemeMode) {
5252
}
5353

5454
export function ThemeProvider(props: { children: ReactNode; forcedTheme?: ThemeMode }) {
55-
// When forcedTheme is provided, use it as the default to avoid flash of wrong theme
56-
const [theme, setTheme] = usePersistedState<ThemeMode>(
55+
// Only use persistence when theme is NOT forced
56+
// When forcedTheme is provided (e.g., from Chromatic modes), bypass persistence entirely
57+
const [persistedTheme, setPersistedTheme] = usePersistedState<ThemeMode>(
5758
UI_THEME_KEY,
58-
props.forcedTheme ?? resolveSystemTheme(),
59+
resolveSystemTheme(),
5960
{
6061
listener: !props.forcedTheme, // Disable listener when theme is forced (avoids conflicts)
6162
}
6263
);
6364

64-
// Use forcedTheme if provided (e.g., from Storybook), otherwise use persisted theme
65-
const activeTheme = props.forcedTheme ?? theme;
65+
// Use forcedTheme if provided, otherwise use persisted theme
66+
// This ensures Chromatic modes (which set forcedTheme) are respected
67+
const activeTheme = props.forcedTheme ?? persistedTheme;
6668

6769
useLayoutEffect(() => {
6870
applyThemeToDocument(activeTheme);
@@ -71,17 +73,17 @@ export function ThemeProvider(props: { children: ReactNode; forcedTheme?: ThemeM
7173
const toggleTheme = useCallback(() => {
7274
// Only allow toggling when not forced
7375
if (!props.forcedTheme) {
74-
setTheme((current) => (current === "dark" ? "light" : "dark"));
76+
setPersistedTheme((current) => (current === "dark" ? "light" : "dark"));
7577
}
76-
}, [props.forcedTheme, setTheme]);
78+
}, [props.forcedTheme, setPersistedTheme]);
7779

7880
const value = useMemo<ThemeContextValue>(
7981
() => ({
8082
theme: activeTheme,
81-
setTheme,
83+
setTheme: setPersistedTheme,
8284
toggleTheme,
8385
}),
84-
[activeTheme, setTheme, toggleTheme]
86+
[activeTheme, setPersistedTheme, toggleTheme]
8587
);
8688

8789
return <ThemeContext.Provider value={value}>{props.children}</ThemeContext.Provider>;

0 commit comments

Comments
 (0)