Color Picker
Color picker control supporting preset swatches, native HTML5 eyedropper pipette, and direct hex or RGB string input.
// Radix — @radix-ui/react-popover
import { CanvasColorPickerPopup, ColorPicker, ColorPickerPopover } from "@shavin/ui";1. Triggerable Popover Color Picker (variant='popover')
Default Pipette Trigger:
Custom Element Trigger:
Component Source
const [color, setColor] = useState("#74C69D");
// Default pipette trigger
<ColorPicker variant="popover" value={color} onChange={setColor} />
// Custom trigger button/swatch
<ColorPicker
variant="popover"
value={color}
onChange={setColor}
trigger={
<button className="flex items-center gap-2 px-3 py-1.5 rounded-[var(--radius-lg)] border border-hairline bg-surface hover:bg-surface-hover">
<span className="w-4 h-4 rounded-full border border-hairline shadow-1" style={{ backgroundColor: color }} />
<span className="font-mono text-xs text-fg">{color}</span>
</button>
}
/>2. Preset Swatches Grid Layout (variant='swatches')
Custom
Selected value:
#46a758Component Source
const [color, setColor] = useState("#46a758");
<ColorPicker variant="swatches" value={color} onChange={setColor} />3. Compact Field Variant (variant='field')
Input field with leading color swatch and trailing pipette eyedropper:
Component Source
const [color, setColor] = useState("#8B5CF6");
<ColorPicker variant="field" value={color} onChange={setColor} className="w-64" />4. Standalone 2D Canvas (variant='canvas')
Canvas value:
#10B981Component Source
const [color, setColor] = useState("#10B981");
<ColorPicker variant="canvas" value={color} onChange={setColor} />5. Custom Label & Label Styling (variant='swatches')
Select Hex
Component Source
<ColorPicker
variant="swatches"
value={color}
onChange={setColor}
customLabel="Select Hex"
customLabelClassName="text-[10px] font-semibold text-accent-contrast uppercase tracking-wider"
/>6. Horizontal Scroll Swatch Row (swatchLayout='scroll')
Custom
Component Source
<ColorPicker variant="swatches" value={color} onChange={setColor} swatchLayout="scroll" />7. Custom Palette Swatches (presets prop)
Custom
Component Source
// ds-lint-disable-next-line no-hex
const customSwatches = [
// ds-lint-disable-next-line no-hex
{ name: "Brand Primary", hex: "#0066FF" },
// ds-lint-disable-next-line no-hex
{ name: "Brand Accent", hex: "#FF5533" },
// ds-lint-disable-next-line no-hex
{ name: "Success Mint", hex: "#10B981" },
];
<ColorPicker variant="swatches" value={color} onChange={setColor} presets={customSwatches} />8. Custom RGB Color Mode (colorMode='rgb', maxSwatches=12)
Custom
Component Source
<ColorPicker variant="swatches" value={color} onChange={setColor} colorMode="rgb" maxSwatches={12} />Props Specification
| Prop | Type | Default | Description |
|---|---|---|---|
| value* | string | — | The currently selected hex color string (e.g. "#46a758"). |
| onChange* | (hex: string) => void | — | Callback fired when the color changes. |
| variant | "popover" | "canvas" | "swatches" | "field" | "default" | triggerable | Visual variant: "popover" (default triggerable popover), "canvas" (inline 2D canvas), "swatches" (preset swatches grid), or "field" (compact input). |
| trigger | React.ReactNode | — | Optional custom trigger element when using popover mode. |
| presets | ColorPickerSwatch[] | — | Preset swatch spectrum. Defaults to Shavin UI's 24 accent swatches. |
| swatchLayout | "grid" | "scroll" | grid | Layout of preset swatches: multi-row grid or single-row horizontal scroll bar. Default "grid". |
| maxSwatches | number | — | Maximum number of swatches to render from presets list. |
| colorMode | "hex" | "rgb" | hex | Format mode for custom color input: "hex" or "rgb". Default "hex". |
| customLabel | React.ReactNode | Custom | Custom label text or element for the custom color input section. Default "Custom". |
| customLabelClassName | string | — | Custom CSS class names to style the custom mode label text/font/size/color. |
| allowCustom | boolean | true | Whether to display the custom eyedropper pipette and text input. Default true. |
| size | "sm" | "md" | "lg" | "full" | "md" | — |
* required