ColorPicker A color selection component with presets, format conversion, and screen picker support.
npx vayu-ui init #one time only
npx vayu-ui add colorpicker
npx vayu-ui add -t colorpicker #with test case needs
Preview Code
Brand Color Choose a primary color for your brand.
Theme Color Select a color for your theme.
Select color. Current color: #3b82f6
This color does not meet contrast requirements.
Minimal Picker Select color. Current color: #10b981
< ColorPicker value = {color} onChange = {setColor}>
< ColorPicker.Label >Brand Color</ ColorPicker.Label >
< ColorPicker.Description >
Choose a primary color for your brand.
</ ColorPicker.Description >
< div className = "flex items-center gap-2" >
< ColorPicker.Trigger />
< ColorPicker.Input />
< ColorPicker.CopyButton />
</ div >
< ColorPicker.Content >
< div className = "flex flex-col gap-4" >
< ColorPicker.Palette />
< ColorPicker.Eyedropper />
< ColorPicker.Presets />
</ div >
</ ColorPicker.Content >
</ ColorPicker >
< ColorPicker value = {color} onChange = {setColor} format = "rgb" >
< ColorPicker.Label >Background Color</ ColorPicker.Label >
< div className = "flex items-center gap-2" >
< ColorPicker.Trigger size = "sm" />
< ColorPicker.Input />
< ColorPicker.CopyButton />
</ div >
< ColorPicker.Content >
< div className = "flex flex-col gap-4" >
< ColorPicker.Palette />
< ColorPicker.Presets columns = { 6 } />
</ div >
</ ColorPicker.Content >
</ ColorPicker >
< ColorPicker validationState = "error" >
< ColorPicker.Label >Theme Color</ ColorPicker.Label >
< ColorPicker.Description >
Select a color for your theme.
</ ColorPicker.Description >
< div className = "flex items-center gap-2" >
< ColorPicker.Trigger />
< ColorPicker.Input />
</ div >
< ColorPicker.Error >
This color does not meet contrast requirements.
</ ColorPicker.Error >
</ ColorPicker >
< ColorPicker.Swatches
label = "Quick Pick"
colors = {[ "#ef4444" , "#f97316" , "#eab308" , "#22c55e" , "#3b82f6" , "#8b5cf6" , "#ec4899" , "#171717" ]}
value = {swatchColor}
onChange = {setSwatchColor}
size = "lg"
columns = { 4 }
/>
< ColorPicker defaultValue = "#6366f1" disabled >
< ColorPicker.Label >Locked Color</ ColorPicker.Label >
< div className = "flex items-center gap-2" >
< ColorPicker.Trigger />
< ColorPicker.Input />
</ div >
</ ColorPicker >
ColorPicker
├── ColorPicker.Label -- Accessible label linked to the input
├── ColorPicker.Description -- Helper text below the label
├── ColorPicker.Error -- Error message (renders only in error state)
├── ColorPicker.Trigger -- Color swatch button that toggles the dropdown
├── ColorPicker.Input -- Text input for hex/rgb/hsl values
├── ColorPicker.CopyButton -- Copies current color to clipboard
└── ColorPicker.Content -- Dropdown panel with positioning
├── ColorPicker.Palette -- Native browser color picker
├── ColorPicker.Eyedropper -- Screen color picker (Chrome/Edge only)
└── ColorPicker.Presets -- Grid of preset color swatches
ColorPicker.Swatches -- Standalone swatch grid (no context required)
Key Context Behavior EnterTrigger Opens the dropdown SpaceTrigger Opens the dropdown EscapeContent (open) Closes dropdown, returns focus TabAny Moves focus to next element
Component Attribute Value Trigger aria-expandedtrue / falseTrigger aria-controlsDropdown ID Trigger aria-labelledbyLabel ID Trigger aria-haspopup"dialog"Input aria-labelledbyLabel ID Input aria-describedbyDescription + error IDs Input aria-invalidtrue when in error stateContent role"dialog"Content aria-modalfalseError role"alert"Error aria-live"polite"Presets / Swatches role"listbox" / "option"Presets / Swatches aria-selectedtrue on active swatchCopyButton aria-labelDynamic: "Copy color" / "Copied!" Eyedropper aria-busytrue while picking
Trigger receives focus via Tab
Content auto-focuses on open via requestAnimationFrame
Escape closes dropdown and returns focus to the trigger
Click outside closes dropdown and maintains focus
All interactive elements have visible focus-visible ring
The trigger announces: "Select color. Current color: {hex value}"
The label is associated with the input via htmlFor and aria-labelledby
Description text is linked to the input via aria-describedby
In error state, the error message is announced via aria-live="polite" and role="alert"
Preset swatches are announced as a listbox with options: "Select color {hex}"
The selected swatch is indicated by aria-selected="true"
The copy button announces "Copied!" after a successful clipboard copy
The eyedropper announces its label and sets aria-busy during active picking
ColorPicker/
├── ColorPicker.tsx
├── ColorPickerContent.tsx
├── ColorPickerCopyButton.tsx
├── ColorPickerDescription.tsx
├── ColorPickerError.tsx
├── ColorPickerEyeDropper.tsx
├── ColorPickerInput.tsx
├── ColorPickerLabel.tsx
├── ColorPickerPalette.tsx
├── ColorPickerPresets.tsx
├── ColorPickerSwatches.tsx
├── ColorPickerTrigger.tsx
├── hooks.ts
├── index.ts
├── types.ts
├── utils.ts
└── README.md
Prop Type Default Description valuestring— Controlled color value (hex) defaultValuestring"#3b82f6"Uncontrolled default color onChange(color: string) => void— Callback when color changes format"hex" | "rgb" | "hsl""hex"Display format in the text input presetsstring[]22 defaults Custom preset color array disabledbooleanfalseDisable all interactions validationState"default" | "error" | "warning" | "success""default"Input validation state defaultOpenbooleanfalseInitial dropdown open state openboolean— Controlled dropdown state onOpenChange(open: boolean) => void— Callback when dropdown toggles
Prop Type Default Description childrenReactNode— Label text optionalbooleanfalseShows "(optional)" text
Prop Type Default Description childrenReactNode— Helper text
Prop Type Default Description childrenReactNode— Error message (only renders in error state)
Prop Type Default Description size"sm" | "md" | "lg""md"Swatch size (32/48/64 px)
Prop Type Default Description placeholderstring"#000000"Input placeholder
Prop Type Default Description copiedTextstring"Copied!"Text shown after copying
Prop Type Default Description side"top" | "bottom""bottom"Preferred vertical position align"start" | "center" | "end""start"Horizontal alignment to trigger sideOffsetnumber8Distance from trigger (px)
Prop Type Default Description labelstring"Pick a color"Accessible label text
Prop Type Default Description labelstring"Pick from screen"Button text unsupportedTextstring"Eyedropper not supported in this browser"Fallback message
Prop Type Default Description labelstring"Preset Colors"Section label colorsstring[]Context presets Override preset colors columnsnumber8Grid column count
Prop Type Default Description colorsstring[]— Array of hex colors valuestring— Currently selected color onChange(color) => void— Callback on swatch click size"sm" | "md" | "lg""md"Swatch size (24/32/40 px) columnsnumber8Grid column count labelstring— Section label disabledbooleanfalseDisable all swatches