ColorPicker component
ColorPicker picks a colour with a saturation and brightness area, a hue slider, an optional transparency slider, a text box that takes hex, rgb() or hsl(), suggested colours and, where the browser has one, a pick-from-screen button. Everything works from the keyboard. ColorField is the form field version: a swatch that opens the picker in a pop-up, next to a text box, and it joins a Form.
Playground
Change a prop on the right and the preview updates. Switch to Code to copy what you see.
An inline picker
Control it with value and onChange, or give defaultValue. onChange gets the colour written in the chosen format (hex, rgb or hsl). onChangeEnd is called when a drag ends or a value is typed, which is the moment to save. swatches adds one-click colours; give { value, label } to name one for screen readers.
const [color, setColor] = useState("#2563eb");
<ColorPicker
value={color}
onChange={setColor}
swatches={["#2563eb", "#16a34a", { value: "#dc2626", label: "Brand red" }]}
/>Transparency and formats
showAlpha adds an opacity slider. With hex the value becomes #2563eb80; with format rgb or hsl it becomes rgb(37 99 235 / 0.5).
<ColorPicker defaultValue="rgb(37 99 235 / 0.5)" format="rgb" showAlpha onChangeEnd={save} />A form field
ColorField takes the same props plus label, description, error, name and validation. Inside a Form the colour is stored under name as a string (empty when none), so required means has a colour.
<Form onSubmit={save}>
<ColorField label="Accent colour" name="accent" validation={{ rules: { required: true } }} />
</Form>Props
The full public API for ColorPicker. Every prop is stable and intentionally typed.
Data
| Prop | Type | Default | Description |
|---|---|---|---|
| value / defaultValue | string | "" | The colour as #2563eb, rgb(…) or hsl(…). value makes it controlled. |
| onChange | (value: string) => void | — | Every change, written in format. |
| onChangeEnd | (value: string) => void | — | ColorPicker only. When a drag ends or a value is typed or picked; use it for saving. |
| format | "hex" | "rgb" | "hsl" | hex | How the value is written. Hex with transparency is #2563eb80. |
| name / validation | string / FieldValidation | — | ColorField only. In a Form: the key the colour is stored under and its rules. |
value / defaultValue
string
default: ""
The colour as #2563eb, rgb(…) or hsl(…). value makes it controlled.
onChange
(value: string) => void
default: —
Every change, written in format.
onChangeEnd
(value: string) => void
default: —
ColorPicker only. When a drag ends or a value is typed or picked; use it for saving.
format
"hex" | "rgb" | "hsl"
default: hex
How the value is written. Hex with transparency is #2563eb80.
name / validation
string / FieldValidation
default: —
ColorField only. In a Form: the key the colour is stored under and its rules.
Appearance
| Prop | Type | Default | Description |
|---|---|---|---|
| showAlpha | boolean | false | Adds a transparency slider. |
| showInput | boolean | true | The text box with the value. |
| size / isReadOnly / placeholder | sm | md | lg / boolean / string | md / false / — | ColorField only. Field size, read-only state and hint text. |
| classNames | Partial<Record<slot, string>> | — | Class per part (ColorPicker: base, area, thumb, hue, alpha, preview, input, swatches, swatch; ColorField: base, label, control, swatch, input, popover, description, error). |
showAlpha
boolean
default: false
Adds a transparency slider.
showInput
boolean
default: true
The text box with the value.
size / isReadOnly / placeholder
sm | md | lg / boolean / string
default: md / false / —
ColorField only. Field size, read-only state and hint text.
classNames
Partial<Record<slot, string>>
default: —
Class per part (ColorPicker: base, area, thumb, hue, alpha, preview, input, swatches, swatch; ColorField: base, label, control, swatch, input, popover, description, error).
Content
| Prop | Type | Default | Description |
|---|---|---|---|
| swatches | Array<string | { value, label? }> | — | Colours to pick with one click. label names a swatch for screen readers. |
| label / description | ReactNode | — | ColorField only. A visible label (it names the text box) and help text. |
| error | ReactNode | boolean | form's error for name | ColorField only. An error message, or true for the invalid look. |
| labels | Partial<ColorPickerLabels> | English | area, saturation, brightness, hue, alpha, value, eyeDropper, swatches, open, dialog. Also set app-wide with LocaleProvider. |
swatches
Array<string | { value, label? }>
default: —
Colours to pick with one click. label names a swatch for screen readers.
label / description
ReactNode
default: —
ColorField only. A visible label (it names the text box) and help text.
error
ReactNode | boolean
default: form's error for name
ColorField only. An error message, or true for the invalid look.
labels
Partial<ColorPickerLabels>
default: English
area, saturation, brightness, hue, alpha, value, eyeDropper, swatches, open, dialog. Also set app-wide with LocaleProvider.
Behavior & states
| Prop | Type | Default | Description |
|---|---|---|---|
| showEyeDropper | boolean | true | A button that picks a colour from the screen, where the browser supports it (Chrome and Edge). |
| isDisabled | boolean | false | Dimmed and not interactive. |
showEyeDropper
boolean
default: true
A button that picks a colour from the screen, where the browser supports it (Chrome and Edge).
isDisabled
boolean
default: false
Dimmed and not interactive.
Accessibility
- The area is a group with two range inputs, Saturation and Brightness. All four arrow keys work on both: left and right change saturation, up and down change brightness, and Shift takes bigger steps.
- Hue and opacity are native range inputs read as degrees and a percent. Sliders are 24px tall to meet the target-size rule.
- The text box applies a value on Enter or blur, and Escape restores the last good value.
- ColorField's swatch button has aria-haspopup="dialog" and aria-expanded. The picker opens in a dialog; Escape or a click outside closes it and returns focus to the swatch.
Best practices
- Give ColorField a visible label; it also names the text box.
- The eye dropper only shows in browsers that support it (Chrome and Edge); the text box and swatches work everywhere.
- Use onChangeEnd, not onChange, to save to a server, so a drag does not send a request for every pixel.
- Do not pass colours that are not CSS colours; an unreadable value leaves the previous colour in place.