fix(react): keep native select options readable in dark mode#1240
fix(react): keep native select options readable in dark mode#1240jackulau wants to merge 2 commits into
Conversation
The native <select> option popup follows the control's opaque background and color-scheme, not option-level styles. bg-transparent left the popup white, so dark-mode options rendered near-white text on a white surface. The dark:bg-input/30 fallback never applied: the dark: variant is gated on a .dark ancestor class this app never sets (theming is prefers-color-scheme driven). Give the select a solid themed surface (bg-popover/text-popover-foreground), add a hover:bg-accent state, and pin color-scheme via useIsDark so the native popup follows the active theme. Fixes the Resume approvals dropdown in setup-mcp and mcp-install-card, and every other NativeSelect. Closes RhysSullivan#1227
Greptile SummaryThis PR fixes unreadable native
Confidence Score: 5/5Safe to merge — the change is narrowly scoped to NativeSelect's className and inline style, with no logic changes elsewhere. The fix correctly replaces dead Tailwind dark: utilities (which never matched due to the app using prefers-color-scheme rather than a .dark class) with an opaque themed surface and a dynamically pinned color-scheme. The useIsDark() hook is already established in the codebase and handles SSR safely. The style spread order (colorScheme first, then ...style) is an intentional API affordance allowing callers to override if needed. No regressions are introduced. No files require special attention. Important Files Changed
Flowchart%%{init: {'theme': 'neutral'}}%%
flowchart TD
A["NativeSelect renders"] --> B["useIsDark()"]
B --> C{"prefers-color-scheme: dark?"}
C -->|yes| D["colorScheme: 'dark'"]
C -->|no| E["colorScheme: 'light'"]
D --> F["<select style={{colorScheme}} className='bg-popover text-popover-foreground'>"]
E --> F
F --> G["Browser native option popup\ninherits opaque bg + matching color-scheme"]
G --> H["Readable in both light & dark mode ✓"]
%%{init: {'theme': 'base', 'themeVariables': {"darkMode": true, "background": "#0d1117", "primaryColor": "#21262d", "primaryTextColor": "#e6edf3", "primaryBorderColor": "#8b949e", "lineColor": "#8b949e", "textColor": "#e6edf3", "edgeLabelBackground": "#161b22", "actorBkg": "#21262d", "actorBorder": "#8b949e", "actorTextColor": "#e6edf3", "actorLineColor": "#8b949e", "signalColor": "#8b949e", "signalTextColor": "#e6edf3", "noteBkgColor": "#373320", "noteBorderColor": "#d4a72c", "noteTextColor": "#f0e6c0", "labelBoxBkgColor": "#21262d", "labelBoxBorderColor": "#8b949e", "labelTextColor": "#e6edf3", "loopTextColor": "#e6edf3", "activationBkgColor": "#30363d", "activationBorderColor": "#8b949e"}}}%%
flowchart TD
A["NativeSelect renders"] --> B["useIsDark()"]
B --> C{"prefers-color-scheme: dark?"}
C -->|yes| D["colorScheme: 'dark'"]
C -->|no| E["colorScheme: 'light'"]
D --> F["<select style={{colorScheme}} className='bg-popover text-popover-foreground'>"]
E --> F
F --> G["Browser native option popup\ninherits opaque bg + matching color-scheme"]
G --> H["Readable in both light & dark mode ✓"]
Reviews (2): Last reviewed commit: "fix(react): drop remaining dead dark: ar..." | Re-trigger Greptile |
The dark: variant is gated on a .dark class the app never sets, so dark:aria-invalid:ring-destructive/40 never applied. Removing it is a no-op at runtime and keeps the component free of dead dark: utilities.
Problem
Native
<select>dropdowns render unreadable option popups in dark mode (#1227). The Resume-approvals dropdown on the MCP connect card is the visible surface, but everyNativeSelectin the console is affected.Root cause
The console themes through
@media (prefers-color-scheme: dark)and never sets a.darkclass, so Tailwind'sdark:utilities (gated on.darkvia@custom-variant) never match and are effectively dead.NativeSelectrelied ondark:bg-input/30for its dark surface and set nocolor-scheme, leaving itbg-transparent. A native option popup follows the control's opaquebackground-colorandcolor-scheme, not<option>styles, so in dark mode the browser drew a light popup and the inherited light text was unreadable.Fix
bg-popover text-popover-foreground(opaque, flips with the theme tokens) plushover:bg-accent.color-schemeto the active theme via the existinguseIsDark()hook, so the browser renders a matching popup.dark:background utilities.NativeSelectis a shared component, so all of its usages are fixed at once.Verification
format:check,lint(0 warnings / 0 errors),typecheck(42/42), and the@executor-js/reacttest suite (189/189) pass.color-schemeand background/text flip correctly with the OS theme (dark#141414/#ededed, light#ffffff/#111111), which is what makes the native popup readable.Fixes #1227