Repository navigation
Description
Problem
The MUI theme in app/src/main.tsx is hard-pinned to palette.mode: 'light'. Dark mode is implemented entirely via CSS custom properties (--bg-page, --ink, --ink-soft, --rule, …) toggled by [data-theme="dark"] on <html> (see app/src/styles/tokens.css and app/src/hooks/useThemeMode.ts).
This works for hand-built components that opt in to the CSS tokens, but every MUI surface is dark-mode-blind: Paper, Popover, Dialog, TextField (placeholder/input/outline), Button hover overlays, Divider, focus rings, action.hover, action.selected, etc. all remain on light-palette values regardless of theme.
The consequence: every component using a MUI surface has to manually patch bgcolor / color / borderColor with var(--bg-*) / var(--ink*) in its sx prop — and inputs need extra & .MuiOutlinedInput-input::placeholder { color: ... } selectors. Easy to forget, inconsistent, and a recurring source of bugs.
Example bug: FeedbackWidget — the FAB, mini-FAB stack, "Thanks!" toast, and the entire popover (Paper + TextFields + secondary text) appeared as light surfaces on the dark page. Fixed locally in #TBD, but the underlying issue is the theme architecture, not the widget.
Proposed solution
Migrate to MUI's CssVarsProvider with both colorSchemes:
const theme = extendTheme({
colorSchemes: {
light: { palette: { /* current light palette */ } },
dark: { palette: { /* dark equivalents */ } },
},
// …
});Map the existing CSS tokens (--bg-page, --bg-surface, --bg-elevated, --ink, --ink-soft, --ink-muted, --rule) into MUI palette tokens so:
background.default←--bg-pagebackground.paper←--bg-elevatedtext.primary←--inktext.secondary←--ink-softdivider←--ruleaction.hoveretc. — tuned per scheme
Switch useThemeMode to toggle MUI's data-mui-color-scheme attribute (or reuse data-theme via attribute config) so MUI and the existing CSS tokens stay in sync from a single signal.
Wins
- MUI components adapt to dark mode automatically — no per-component
sxpatches - Single source of truth for both schemes
- Keeps CSS-variables performance (MUI v6+ emits CSS vars internally)
- Removes the recurring "I forgot to dark-mode this surface" bug class
Scope / risk
- Touches every component that currently overrides
bgcolor/colorwithvar(--bg-*)(can usually be deleted, not replaced) - Visual regression risk on every surface — needs a screenshot pass in both modes
- Should be its own PR; no need to bundle with feature work
Out of scope
- The local fix in #TBD addresses the FeedbackWidget symptom. This issue is the structural cure.
Activity
fix(feedback-widget): dark-mode adaptation + clearer placeholder (#7282)