Skip to content

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.

Forms15 propsAccessibility notes

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

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

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

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

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.