Color Picker
Picks a colour from an area, channel sliders, swatches or the eyedropper.
Usage
import {
ColorPicker,
ColorPickerArea,
ColorPickerAreaThumb,
ColorPickerContent,
ColorPickerControl,
ColorPickerSlider,
ColorPickerTrigger,
ColorPickerValue,
ColorPickerValueSwatch,
} from "@kanzo-tech/ui";<ColorPicker defaultValue="#c97a1e">
<ColorPickerControl>
<ColorPickerTrigger asChild>
<Button variant="outline">
<ColorPickerValueSwatch className="size-4" />
<ColorPickerValue />
</Button>
</ColorPickerTrigger>
</ColorPickerControl>
<ColorPickerContent>
<ColorPickerArea>
<ColorPickerAreaThumb />
</ColorPickerArea>
<ColorPickerSlider channel="hue" />
</ColorPickerContent>
</ColorPicker>value and defaultValue are plain strings here — Ark wants a parsed Color object, and
this wrapper runs parseColor for you. parseColor is re-exported if you need one directly. safeParseColor is exported beside it and is the one to reach for on a string you did not
write: parseColor throws on anything it cannot read, and this returns undefined instead — an
empty field and a typo are the ordinary states of a colour input, not exceptions.
A hidden input is rendered inside the root, so the picker submits with a surrounding form.
Anatomy
Three parts are not in the tree. ColorPickerView is the column that holds the area and the sliders,
and it takes Ark's format — it is how one picker shows an rgba view and an hsla one without
two pickers. ColorPickerSwatchPreview is the round chip of the current colour, sized off the
InputGroup it sits in, and it is pointer-events-none: a preview, never a target. And
ColorPickerTransparencyGrid is the chequerboard that goes behind a swatch so alpha reads as
alpha rather than as a paler colour — ColorPickerSwatchPreview already lays one down, and this is
exported for the swatch you draw yourself.
<ColorPicker>
<ColorPickerControl>
<ColorPickerTrigger />
<ColorPickerEyeDropperTrigger />
<ColorPickerInput channel="hex" />
<ColorPickerContent> ← portalled + positioned for you
<ColorPickerArea>
<ColorPickerAreaThumb />
<ColorPickerSlider channel />
<ColorPickerSwatchGroup>
<ColorPickerSwatchTrigger value>
<ColorPickerSwatch value />
<ColorPickerSwatchIndicator />Swatches and eyedropper
ColorPickerEyeDropperTrigger renders a Button, so it takes variant and size. The
browser's EyeDropper API is not universal — the trigger is a convenience, never the only path
to a colour.
These parts only work inside a picker
ColorPickerSwatch and friends are not a general colour strip, and cannot be borrowed as one:
each calls useColorPickerContext, which is strict and throws outside a root; the
indicator's data-state="checked" is color.isEqual(value) against the single colour the
machine holds; and every trigger is a button announced as select #2e3440 as the color.
Use them when the colour is the value being edited. When it merely pictures a value that
has a name — a palette, a series, a theme — that is Swatch,
which is aria-hidden and never focusable.
API Reference
ColorPicker
| Prop | Type | Default |
|---|---|---|
value | string | — |
defaultValue | string | — |
positioning | PositioningOptions | { placement: "top-start" } |
lazyMount | boolean | true |
unmountOnExit | boolean | true |
ColorPickerArea
| Prop | Type | Default |
|---|---|---|
showDots | boolean | false |
ColorPickerInput
| Prop | Type | Default |
|---|---|---|
channel | ExtendedColorChannel | "hex" |
ColorPickerEyeDropperTrigger
| Prop | Type | Default |
|---|---|---|
variant | ButtonProps["variant"] | "outline" |
size | ButtonProps["size"] | "icon-md" |
useColorPicker re-exports Ark's useColorPickerContext.
ColorPickerProps is exported, so a wrapper can take the same props without restating them.
ColorPickerChangeDetails is Ark's change details plus the one format most consumers actually
store: the machine's format is "rgba" | "hsla" | "hsba" and has no "hex" member, so
valueAsString is never hex and this adds it.