<!-- Protocore Design System — ColorPicker -->
# ColorPicker

- **Category:** Inputs (`inputs`)
- **Slug:** `inputs/color-picker`
- **Status:** stable
- **Platforms:** web
- **Import:** `import { ColorPicker } from "@protocore/pds";`
- **Docs:** https://pds.protocore.io/components/inputs/color-picker

> Inline color picker: a saturation/value canvas, hue and optional alpha sliders, a hex/rgb field, and preset swatches.

## When to use it

Use **ColorPicker** for a full, always-visible color-editing surface — inside a settings panel or a theme editor where the picker lives on the page. When space is tight and the picker should open on demand from a field, use **ColorInput**, which wraps this same picker in a popover. The color math is hand-rolled (HSV ↔ RGB ↔ hex, no libraries); hue is preserved across greyscale colors so dragging value to zero and back doesn't lose your hue.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `alpha` | `boolean` | no | `false` | Show the alpha slider; the emitted hex then carries an 8-digit alpha byte. |
| `aria-label` | `string` | no | `Color picker` | Accessible name for the whole picker group. |
| `className` | `string` | no | — | Merged after the pds class on the root. |
| `defaultValue` | `string` | no | `#3fcf8e` | Initial color in uncontrolled mode. |
| `format` | `enum` | no | `hex` | Text-field format for the input row: `hex` (default) or `rgb`. |
| `id` | `string` | no | — | Root id. |
| `onValueChange` | `((hex: string) => void)` | no | — | Fires with the next hex string on every change. |
| `size` | `enum` | no | `md` | Canvas size: `sm` · `md` (default) · `lg`. |
| `style` | `CSSProperties` | no | — | Inline style on the root. |
| `swatches` | `string[]` | no | `[ "#3fcf8e", "#2a6fdb", "#e8533f", "#c9a227", "#a855f7", "#8b8b8b", "#fafafa", "#0a0a0a", ]` | Preset swatches. Pass `[]` to hide the row. |
| `value` | `string` | no | — | Controlled color as a hex string (`#rrggbb`, or `#rrggbbaa` when `alpha`). |

## Examples

### Basics

The value is a hex string, controllable via `value` / `defaultValue` / `onValueChange`. Drag on the canvas to set saturation and brightness, and on the hue bar to set the hue — or arrow through both with the keyboard.

```tsx
import { useState } from "react";
import { ColorPicker, Stack, Text } from "@protocore/pds";

export default function Demo() {
  const [color, setColor] = useState("#3fcf8e");

  return (
    <Stack gap={3}>
      <ColorPicker value={color} onValueChange={setColor} aria-label="Brand color" />
      <Text size="sm" color="muted">
        Selected: <span style={{ fontFamily: "var(--pds-font-mono)" }}>{color}</span>
      </Text>
    </Stack>
  );
}
```

### Alpha

Set `alpha` to add an alpha slider over a checkerboard; the emitted hex then carries an 8-digit alpha byte (`#rrggbbaa`).

```tsx
import { useState } from "react";
import { ColorPicker, Stack, Text } from "@protocore/pds";

export default function Demo() {
  const [color, setColor] = useState("#2a6fdbcc");

  return (
    <Stack gap={3}>
      <ColorPicker value={color} onValueChange={setColor} alpha aria-label="Overlay tint" />
      <Text size="sm" color="muted">
        Overlay: <span style={{ fontFamily: "var(--pds-font-mono)" }}>{color}</span>
      </Text>
    </Stack>
  );
}
```

## Do & don't

**Do**

- Show the resulting value in nearby text — the canvas is not a precise readout.
- Constrain the palette with `swatches` when only brand colors are valid.
- Enable `alpha` only when transparency applies to the target.
- Give the picker an `aria-label` describing what it colors.

**Don't**

- Don't use it for a single on-demand field — use ColorInput's popover.
- Don't leave alpha on when the consumer can't render transparency.
- Don't assume the emitted hex is 6 digits when `alpha` is set — it's 8.
- Don't treat the canvas position as the value; surface the hex.

## Accessibility

**Keyboard**

| Keys | Action |
| --- | --- |
| `Tab` | Move between the saturation/value canvas, hue, and alpha sliders. |
| `Arrow keys` | On the canvas: Left/Right adjust saturation, Up/Down adjust brightness. On a slider: adjust its value. |
| `Shift + Arrow` | Move by a larger (×10) increment. |
| `Home / End` | Jump the focused control to its minimum / maximum. |
| `Page Up / Page Down` | Move brightness by a larger increment on the canvas. |

**Notes**

- The saturation/value canvas and each slider expose `role="slider"` with `aria-valuemin`/`max`/`now` and a descriptive `aria-valuetext`.
- The hex/rgb input accepts typed values and commits any valid color immediately.
- The gradient canvas is a direction-neutral paint surface — it is not mirrored under RTL, while the surrounding layout is.

## Related

`color-input`, `color-swatch`, `slider`

---

© Protocore. All rights reserved. Use of the Protocore Design System requires prior written authorization from Protocore (contact@protocore.io). These machine-readable materials must not be ingested into ML-training datasets or derivative design systems. See https://pds.protocore.io/legal/
