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

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

> A sunken hex/rgb field with a leading swatch that opens a ColorPicker in a popover — clearable and controllable.

## When to use it

Use **ColorInput** for an on-demand color field in a form — a compact sunken control that reads like an **Input** and opens the full **ColorPicker** only when needed. When the picker should always be visible (a theme editor, a settings panel), embed **ColorPicker** directly instead. The field accepts typed hex or `rgb()` and commits any valid color immediately; invalid partial text is kept without committing. Wrap it in a **Field** for a label, hint, and error wiring.

## Props

| Prop | Type | Required | Default | Description |
| --- | --- | --- | --- | --- |
| `alpha` | `boolean` | no | `false` | Include an alpha channel in the picker and the emitted value. |
| `aria-label` | `string` | no | — | Accessible label for the text field. |
| `className` | `string` | no | — | Merged after the pds class on the root. |
| `clearable` | `boolean` | no | `false` | Show a clear (×) button once a value is set. |
| `defaultValue` | `string` | no | — | Initial color in uncontrolled mode. |
| `disabled` | `boolean` | no | `false` | Disable the control. |
| `format` | `enum` | no | `hex` | Text-field format: `hex` (default) or `rgb`. |
| `id` | `string` | no | — | Root id — also labels the text field. |
| `invalid` | `boolean` | no | `false` | Mark the field invalid — danger border plus `aria-invalid`. |
| `onValueChange` | `((value: string) => void)` | no | — | Fires with the next hex string, or `undefined` when cleared. |
| `placeholder` | `string` | no | `#000000` | Placeholder for the empty field. |
| `size` | `enum` | no | `md` | Control height: `sm` (32) · `md` (36, default) · `lg` (40). |
| `swatches` | `string[]` | no | — | Preset swatches passed through to the picker. |
| `value` | `string` | no | — | Controlled color as a hex string. |

## Examples

### Basics

The field shows the hex value with a leading ColorSwatch. Click the swatch to open the picker; type a valid hex to update it live. Value is controllable via `value` / `defaultValue` / `onValueChange`, and `onValueChange` fires `undefined` when cleared.

```tsx
import { useState } from "react";
import { ColorInput, Field } from "@protocore/pds";

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

  return (
    <div style={{ maxWidth: 260 }}>
      <Field label="Brand accent" hint="Click the swatch to open the picker">
        <ColorInput value={color} onValueChange={setColor} clearable />
      </Field>
    </div>
  );
}
```

### Alpha & rgb

Set `format="rgb"` to display an `rgb()`/`rgba()` string, and `alpha` to include an alpha channel in both the picker and the emitted value.

```tsx
import { useState } from "react";
import { ColorInput, Field } from "@protocore/pds";

export default function Demo() {
  const [tint, setTint] = useState<string | undefined>("#0a0a0acc");

  return (
    <div style={{ maxWidth: 260 }}>
      <Field label="Overlay tint" hint="rgb() format with an alpha channel">
        <ColorInput value={tint} onValueChange={setTint} alpha format="rgb" clearable />
      </Field>
    </div>
  );
}
```

## Do & don't

**Do**

- Wrap it in a `Field` for a visible label, or pass `aria-label`.
- Use `clearable` when an empty (no color) value is valid.
- Match `format` and `alpha` to what the consuming system stores.
- Allow direct hex entry alongside the picker.

**Don't**

- Don't use it where the picker should stay open — use ColorPicker.
- Don't leave it unlabelled; the swatch and field need an accessible name.
- Don't expect a committed value from invalid partial text — only valid colors commit.
- Don't enable `alpha` if the target can't store or render transparency.

## Accessibility

**Keyboard**

| Keys | Action |
| --- | --- |
| `Tab` | Focus the swatch trigger, then the text field. |
| `Enter / Space` | On the swatch trigger: open the picker popover. |
| `Escape` | Close the picker popover, returning focus to the trigger. |
| `Type` | Enter a hex or rgb() value directly; valid input commits immediately. |

**Notes**

- The leading swatch is a `<button>` (`aria-haspopup="dialog"`) that opens the picker; the picker is a Radix Popover with full focus management and dismissal.
- The text field carries `aria-invalid` when `invalid` is set, matching the Input contract.
- Clearing (the × button or emptying the field) emits `undefined` and shows the checkered empty swatch.

## Related

`color-picker`, `color-swatch`, `input`, `field`

---

© 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/
