Color Picker
HSL-native color picker that edits an HSL triplet directly via three sliders (H/S/L). Hex input is a display adapter; sliders are the source of truth so the value round-trips losslessly through the `@hex-core/tokens` triplet format.
Installation
pnpm dlx @hex-core/cli add color-pickerUsage
import { Color Picker } from "@/components/ui/color-picker"Edit a token live
Bind a state variable to a CSS custom property to preview a token edit in real time.
const [color, setColor] = React.useState("240 5.9% 10%");
return (
<div style={{ "--primary": color } as React.CSSProperties}>
<ColorPicker value={color} onChange={setColor} aria-label="Primary color" />
<Button>Live preview</Button>
</div>
);Disabled
Prevent edits while a parent operation is in flight.
<ColorPicker value="240 5.9% 10%" onChange={() => {}} disabled />API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
valuerequired | string | — | Current color as an HSL triplet string (`"<H> <S>% <L>%"`, e.g. `"240 5.9% 10%"`). Match the format used by `@hex-core/tokens`. |
onChangerequired | function | — | Called with the next HSL triplet when the user drags a slider or commits a valid hex value. Not called for invalid hex input. |
disabled | boolean | false | Disable interaction. Trigger renders dimmed; mouse and keyboard activation are blocked by the native `disabled` attribute. |
aria-label | string | "Pick color" | Accessible name for the trigger button. |
className | string | — | Additional class names merged onto the trigger. |
AI Guidance
When to use
Use whenever the user is editing a color that will round-trip through the `@hex-core/tokens` HSL triplet format — token editors, theme builders, branding panels, custom-color surfaces in design tools.
When not to use
Don't use for picking a color from a fixed palette — use a `Select` or `RadioGroup` of swatches. Don't use for image-based color sampling (eyedropper) — that's a separate primitive. Don't reach for ColorPicker when only a hex string matters: bind it directly to `<input type="color">` for the simplest cases.
Common mistakes
- Treating the value as hex — the prop is an HSL triplet, not a hex string. Use `hexToHslTriplet` and `hslTripletToHex` from `@hex-core/components/lib/color` if you need to bridge.
- Forgetting to wrap the value in `hsl(...)` when applying it as a CSS color: `style={{ color: \`hsl(${value})\` }}`.
- Calling `onChange` synchronously inside a parent's render — the picker batches slider updates and that pattern can desync controlled state.
Accessibility
Each slider has a per-axis `aria-label` (Hue / Saturation / Lightness). The trigger button needs an explicit `aria-label` describing what color is being edited (e.g. `"Primary color"`) — the default `"Pick color"` is generic. The hex input is keyboard-accessible and round-trips with the sliders.
Token budget: 350