Description
An instance that sets NEXT_PUBLIC_COLOR_THEME_DEFAULT=light may still serve the dark theme to a first-time visitor whose operating system prefers dark. The configured default wins the initial paint and then loses to the OS preference on hydration.
Needs confirmation in a production-like run before being treated as a real defect — see the open question below.
Details
SettingsColorTheme's mount effect reads the chakra-ui-color-mode cookie and, when it is absent, falls back to prefers-color-scheme. It never consults config.shell.topBar.colorTheme.default, and it writes the resolved value back into the cookies, so the OS-derived choice becomes sticky:
https://github.com/blockscout/frontend/blob/main/src/shell/top-bar/settings/color-theme/SettingsColorTheme.tsx#L45-L63
ColorModeProvider does pass the configured default to next-themes, which is why the first paint is correct:
https://github.com/blockscout/frontend/blob/main/src/toolkit/chakra/color-mode.tsx#L20
colorThemeMiddleware is presumably what normally prevents this, by planting the default cookie when none is present:
https://github.com/blockscout/frontend/blob/main/src/server/middlewares/colorTheme.ts
Steps to reproduce
Observed on a dev server with NEXT_PUBLIC_COLOR_THEME_DEFAULT=light and a browser reporting prefers-color-scheme: dark:
- Clear the
chakra-ui-color-mode and chakra-ui-color-theme cookies.
- Reload the homepage.
document.documentElement.className is light immediately after load, then becomes dark once the app hydrates, and both cookies are rewritten to dark.
Open question
colorThemeMiddleware is wired up in proxy.ts with a matcher that covers /, but a plain request to / returned no theme cookie in dev:
curl -s -D - -o /dev/null http://localhost:3000/ | grep -i set-cookie
Only uuid came back. Worth checking whether that middleware runs at all under next dev (Next 16 renamed middleware.ts to proxy.ts) and whether it behaves differently in a container. If the middleware does reliably fire in production, the impact is limited to cases where the cookie is missing or cleared client-side.
Expected behavior
A visitor with no theme cookie gets the theme configured by NEXT_PUBLIC_COLOR_THEME_DEFAULT, regardless of their OS setting. The OS preference should only apply when the instance sets no default.
Possible fix, if confirmed: make the no-cookie branch in SettingsColorTheme prefer config.shell.topBar.colorTheme.default and fall back to prefers-color-scheme only when it is unset.
Description
An instance that sets
NEXT_PUBLIC_COLOR_THEME_DEFAULT=lightmay still serve the dark theme to a first-time visitor whose operating system prefers dark. The configured default wins the initial paint and then loses to the OS preference on hydration.Needs confirmation in a production-like run before being treated as a real defect — see the open question below.
Details
SettingsColorTheme's mount effect reads thechakra-ui-color-modecookie and, when it is absent, falls back toprefers-color-scheme. It never consultsconfig.shell.topBar.colorTheme.default, and it writes the resolved value back into the cookies, so the OS-derived choice becomes sticky:https://github.com/blockscout/frontend/blob/main/src/shell/top-bar/settings/color-theme/SettingsColorTheme.tsx#L45-L63
ColorModeProviderdoes pass the configured default tonext-themes, which is why the first paint is correct:https://github.com/blockscout/frontend/blob/main/src/toolkit/chakra/color-mode.tsx#L20
colorThemeMiddlewareis presumably what normally prevents this, by planting the default cookie when none is present:https://github.com/blockscout/frontend/blob/main/src/server/middlewares/colorTheme.ts
Steps to reproduce
Observed on a dev server with
NEXT_PUBLIC_COLOR_THEME_DEFAULT=lightand a browser reportingprefers-color-scheme: dark:chakra-ui-color-modeandchakra-ui-color-themecookies.document.documentElement.classNameislightimmediately after load, then becomesdarkonce the app hydrates, and both cookies are rewritten todark.Open question
colorThemeMiddlewareis wired up inproxy.tswith a matcher that covers/, but a plain request to/returned no theme cookie in dev:curl -s -D - -o /dev/null http://localhost:3000/ | grep -i set-cookieOnly
uuidcame back. Worth checking whether that middleware runs at all undernext dev(Next 16 renamedmiddleware.tstoproxy.ts) and whether it behaves differently in a container. If the middleware does reliably fire in production, the impact is limited to cases where the cookie is missing or cleared client-side.Expected behavior
A visitor with no theme cookie gets the theme configured by
NEXT_PUBLIC_COLOR_THEME_DEFAULT, regardless of their OS setting. The OS preference should only apply when the instance sets no default.Possible fix, if confirmed: make the no-cookie branch in
SettingsColorThemepreferconfig.shell.topBar.colorTheme.defaultand fall back toprefers-color-schemeonly when it is unset.