Skip to main content

ColorPicker

betav0.1.0

A single colour field with a popover panel: an editable hex trigger with an inline swatch, and a panel offering a saturation/brightness area, hue slider, optional alpha slider, an eyedropper, a format selector (HEX/RGB/HSL/HSB), value inputs, and an optional preset-swatch grid. Vendored from DiceUI's radix-base colour picker and re-tokenized to FDS; output is a hex string by default.

Variants

Applies to the product navigation bar
Alpha slider + opacity input, emits #RRGGBBAA
Preset grid defaults to the official Filigran palette

Examples

<ColorPicker label="Label color" defaultValue="#009EDB" onValueChange={setColor} />
<ColorPicker
  label="Theme background"
  value={color}
  onValueChange={setColor}
  helperText="Applies to the product navigation bar"
/>
<ColorPicker label="Accent" alpha value={rgba} onValueChange={setRgba} />
<ColorPicker label="Brand" showSwatches value={color} onValueChange={setColor} />
<ColorPicker label="Status" error="Pick a color" required onValueChange={setColor} />

Props

PropType
valuestring — Controlled colour value. Hex by default (#RRGGBB); #RRGGBBAA when alpha is enabled
defaultValuestring — Uncontrolled initial value
onValueChange(value: string) => void — Fired on every colour change; emits a hex string (#RRGGBBAA when alpha is on) for a resolved colour, "" when cleared, or a non-parsing hex-field draft (e.g. "red") verbatim so a controlled parent never holds a stale value
labelReactNode — Field label. Omit → aria-label or aria-labelledby required (RULE-01)
infoTooltipReactNode — Info affordance rendered next to the label (caller-owned)
helperTextReactNode — Help text under the field
errorstring — Error message. String only (no boolean) — presence toggles the error visual and replaces helperText (RULE-04)
requiredboolean — Renders the `*` marker (when a label is present) and sets aria-required
disabledboolean — Disables the trigger and the whole panel (RULE-06)
placeholderstring — Placeholder shown in the empty trigger. Defaults to "Select color"
alphaboolean — Enables the alpha slider + opacity input. Off by default; enabling it changes the output shape to #RRGGBBAA (RULE-03)
formatsColorFormat[] — Formats offered in the panel selector. Defaults to ["hex","rgb","hsl","hsb"]
formatColorFormat — Initial/controlled panel format. Defaults to "hex"
showSwatchesboolean — Shows the preset-swatch grid. Off by default (RULE-07)
presetsreadonly string[] — Preset colours. Defaults to the official Filigran palette (DEFAULT_PRESETS)
eyeDropperboolean — Shows the eyedropper button, auto-hidden where unsupported. Defaults to true (RULE-08)
namestring — Form field name for the hidden input
classNamestring — Additional CSS classes on the outer wrapper (RULE-12)

Accessibility

2.1 AAWCAG pass

Trigger is an editable hex <input> paired with a palette IconButton that opens a Radix Popover (aria-expanded, aria-haspopup) — the hex value is keyboard-editable in BOTH the trigger and the panel's value input (RULE-09). The area is a role="slider" 2D control with an aria-valuetext of the current saturation/brightness and arrow-key stepping (Shift = ×10) for WCAG 2.1.1. The hue and alpha sliders are the vendored colour sliders (gradient track), not the FDS Slider (RULE-10); they inherit role=slider + aria-valuemin/max/now from @radix-ui/react-slider and align their thumb tokens (--icon-default) to the FDS Slider for family consistency. Each value input is a labelled <input> (per-channel aria-labels); preset swatches are labelled buttons with aria-pressed. Colour is never signalled by chroma alone — the hex/channel text always states the value (WCAG 1.4.1). The eyedropper is a best-effort FDS IconButton, auto-hidden where window.EyeDropper is unsupported (Firefox/Safari) — the panel reads correctly without it (RULE-08). An unlabeled field warns in development (console.warn, never a throw), matching Input. The field's disabled tones are contrast-exempt as an inactive component (WCAG 1.4.3 Note 1): the trigger input's bg/text come from `disabled:` variants, while the label, required marker and helper text switch to text-input-disabled through explicit tone selection — both apply only when the whole field is disabled; the three intrinsic gradients (hue rainbow, area saturation/brightness, alpha checkerboard) are decorative and carry no text, so they are not contrast pairs (RFC §3.4). Focus uses the standard FDS ring (ring-focus + ring-offset-focus) on every interactive element.