# Give Native Selects Explicit Colors

**MUST** · **ID:** `design-select-colors` · **Category:** design
**Source:** [Vercel](https://github.com/vercel-labs/agent-skills/blob/main/skills/web-design-guidelines/SKILL.md)
**Interactive version:** https://ui-guides-agent-rules.netlify.app/principles/design-select-colors

> MUST: Set BOTH `background-color` and `color` on every native `<select>` from your tokens (and pair them with `color-scheme` so the option popup follows) — form controls do not inherit them, so styling only the text leaves near-white on the platform's white Field background in Windows dark mode.

Set both background-color and color on every native <select>, never just one

Form controls do not inherit `color` and `background-color` the way ordinary elements do — the browser supplies its own. Style only the text for your dark theme and the platform keeps its light Field background underneath, giving you near-white text on white: the value and every option in the popup become unreadable. This bites hardest on Windows, where the UA background is least likely to follow your theme. Declare both properties from your tokens, and pair them with `color-scheme` so the native option list is drawn dark too.

## Bad — do not do this

`design-select-colors-bad`

```tsx
/**
 * BAD: The dark theme sets `color` on the <select> but never `background-color`,
 * so the control keeps the UA's *light* Field background. Light text lands on a
 * light background and the value — plus every option in the popup — is unreadable.
 *
 * This is the classic Windows dark-mode failure: authors style the text, forget the
 * fill, and the platform supplies a light one.
 */
export function SelectColorsBad() {
  return (
    <div className="w-full max-w-md space-y-4">
      <div className="bg-muted rounded-md p-3 font-mono text-xs overflow-x-auto">
        <pre className="text-error">{`select {
  color: var(--foreground); /* near-white */
  /* background-color never set →      */
  /* the UA paints its own light Field */
}`}</pre>
      </div>

      {/* Dark page whose <select> inherits a light UA background */}
      <div
        className="dark bg-background text-foreground border border-border rounded-lg p-4 space-y-3"
        style={{ colorScheme: 'light' }}
      >
        <label className="block space-y-1">
          <span className="text-xs font-medium text-muted-foreground">Environment</span>
          <select
            defaultValue="production"
            className="text-foreground w-full rounded-md p-2 text-sm"
          >
            <option value="production">Production</option>
            <option value="preview">Preview</option>
            <option value="development">Development</option>
          </select>
        </label>

        <label className="block space-y-1">
          <span className="text-xs font-medium text-muted-foreground">Region</span>
          <select
            defaultValue="iad1"
            className="text-foreground w-full rounded-md p-2 text-sm"
          >
            <option value="iad1">Washington, D.C.</option>
            <option value="fra1">Frankfurt</option>
            <option value="hnd1">Tokyo</option>
          </select>
        </label>
      </div>

      <p className="text-xs text-error">
        Both selects are set to a value — you just can&apos;t read it. Light text on the
        UA&apos;s light Field background.
      </p>
    </div>
  );
}
```

## Good — do this

`design-select-colors-good`

```tsx
/**
 * GOOD: The <select> declares BOTH `background-color` and `color` from theme tokens,
 * and the scope declares `color-scheme: dark` so the native option popup is drawn
 * dark too. Nothing is left to the platform's guess.
 */
export function SelectColorsGood() {
  return (
    <div className="w-full max-w-md space-y-4">
      <div className="bg-muted rounded-md p-3 font-mono text-xs overflow-x-auto">
        <pre className="text-foreground">{`select {
  color: var(--foreground);
  background-color: var(--card); /* both! */
}
/* and on the scope: */
color-scheme: dark; /* styles the popup */`}</pre>
      </div>

      {/* Dark page whose <select> declares its own fill */}
      <div
        className="dark bg-background text-foreground border border-border rounded-lg p-4 space-y-3"
        style={{ colorScheme: 'dark' }}
      >
        <label className="block space-y-1">
          <span className="text-xs font-medium text-muted-foreground">Environment</span>
          <select
            defaultValue="production"
            className="bg-card text-foreground border border-border w-full rounded-md p-2 text-sm"
          >
            <option value="production">Production</option>
            <option value="preview">Preview</option>
            <option value="development">Development</option>
          </select>
        </label>

        <label className="block space-y-1">
          <span className="text-xs font-medium text-muted-foreground">Region</span>
          <select
            defaultValue="iad1"
            className="bg-card text-foreground border border-border w-full rounded-md p-2 text-sm"
          >
            <option value="iad1">Washington, D.C.</option>
            <option value="fra1">Frankfurt</option>
            <option value="hnd1">Tokyo</option>
          </select>
        </label>
      </div>

      <p className="text-xs text-success">
        Value and options stay readable: explicit fill, explicit text color, and a
        matching color-scheme for the popup.
      </p>
    </div>
  );
}
```

## References

- [MDN: <select>](https://developer.mozilla.org/en-US/docs/Web/HTML/Reference/Elements/select)
- [MDN: color-scheme](https://developer.mozilla.org/en-US/docs/Web/CSS/Reference/Properties/color-scheme)
