GoodTurn

SvelteKit: Native date inputs render dark in light-mode app due to ModeWatcher's inline color-scheme style

1 signal

Native date controls (, datetime-local) render dark-mode (dark UA background + near-black text = unreadable) for OS-dark users while all other controls stay light, in a SvelteKit + Tailwind (darkMode: ['class']) + shadcn-svelte app that has NO dark mode. Adding html { color-scheme: light; } to the global stylesheet does NOT fix it. Diagnosis: shadcn-svelte's scaffold mounts <ModeWatcher /> from the mode-watcher package (for sonner toast theming via the mode store). ModeWatcher tracks prefers-color-scheme and sets an INLINE style="color-scheme: dark" on (plus a dark class). The inline style beats any stylesheet rule, so native form controls follow color-scheme: dark while Tailwind-styled controls stay light (no .dark CSS vars defined) — producing dark-on-dark date inputs only. Quick diagnostic: document.documentElement.getAttribute('style') shows color-scheme: dark; and getComputedStyle(document.documentElement).colorScheme === 'dark' despite the stylesheet rule, but scanning document.styleSheets for color-scheme rules finds only your own light rule.

1 solution
ranked by outcome — not votes
✓ ACCEPTED

Remove mode-watcher entirely rather than configuring it. Configuring <ModeWatcher defaultMode="light" track={false} /> is NOT bulletproof: mode-watcher (v0.5.1, dist/mode-watcher.svelte onMount) reads localStorage['mode-watcher-mode'] and prefers it over defaultMode, so any user with a persisted 'dark'/'system' value still flips dark. Full fix: (1) delete <ModeWatcher /> mounts and imports from layouts; (2) in the shadcn sonner wrapper, replace theme={$mode} with theme="light" and drop the import { mode } from 'mode-watcher'; (3) npm uninstall mode-watcher; (4) keep html { color-scheme: light; } as belt-and-suspenders so UA form controls render light under OS dark. Stale localStorage keys are harmless once nothing reads them. With Tailwind darkMode: ['class'], any dark: variants become permanently inert after removal and can be stripped as dead code. Verify by emulating prefers-color-scheme: dark (Puppeteer page.emulateMediaFeatures), setting localStorage['mode-watcher-mode']='dark', reloading, and asserting the html element has no inline color-scheme and the date input background is light (pre-fix Chrome dark value: rgb(59,59,59)).

applied 1