# ColorSelector

> Slug: `color-selector` · Category: Form Controls

## When to use

- Selecting a single color or material swatch from a small set (product configurator, theme picker, accessory choice).
- When the visual swatch IS the label and a text label would be redundant.

## When NOT to use

- More than ~10 swatches or named option labels — use `RadioGroup` or `StyledRadioGroup` with leading decoration.
- Free-form color entry — use a native color input or a custom picker.
- Multiple selection — use `Chips variant="toggle"`.

## Variants & decision tree

The component is a radio group of color swatches. Each option supports CSS color values OR an image URL via the `color` field.

| Need | Approach |
|---|---|
| Solid color | `color: '#FF5733'` |
| Pattern/material | `color: 'url(/patterns/wood.png)'` |
| Out-of-stock | `isUnavailable: true` |

## States

Default, hovered, focused, checked (selected), unavailable (disabled with strike-through visual).

## Props

| Prop | Type | Default | Description |
|---|---|---|---|
| `groupName` | `string` | — | Required. `name` for the radio group. |
| `options` | `ColorSelectorOption[]` | — | Required. Swatches to render. |
| `value` | `string` | — | Controlled selected option `id`. |
| `defaultValue` | `string` | — | Uncontrolled initial selection. |
| `onChange` | `(optionId, event) => void` | — | Fired on selection. |
| `inverse` | `boolean` | `false` | Dark-background styling. |

`ColorSelectorOption`: `{ id, color, a11yLabel, isUnavailable, checked?, hover?, focused? }`.

## Usage examples

```tsx
const [color, setColor] = useState('red');

<ColorSelector
  groupName="phone-color"
  value={color}
  onChange={(id) => setColor(id)}
  options={[
    { id: 'red', color: '#E20074', a11yLabel: 'Magenta', isUnavailable: false },
    { id: 'blk', color: '#000000', a11yLabel: 'Black', isUnavailable: false },
    { id: 'wht', color: '#FFFFFF', a11yLabel: 'White', isUnavailable: false },
    { id: 'gld', color: '#D4AF37', a11yLabel: 'Gold', isUnavailable: true },
  ]}
/>
```

## Composition

Pair with a label or heading describing what the user is choosing (e.g., "Color: Magenta") — ColorSelector itself does not render a legend. For more complex content (price, stock badge), use `StyledRadioGroup` with `leadingDecoration` instead.

## Accessibility

Each option requires an `a11yLabel` — this becomes the radio's accessible name (the visual swatch alone has no text). `isUnavailable: true` visually disables and prevents selection. Provide a heading or visible label adjacent to the group so the purpose is announced.

## Do / Don't

- DO supply a meaningful `a11yLabel` per swatch ("Galactic Black", not "Color 1").
- DO render a heading above the swatches.
- DON'T omit `groupName` — radios won't be mutually exclusive without it.
- DON'T use only color to convey availability; `isUnavailable` adds visual + a11y treatment.
