Shadcn Color Picker for React and Tailwind
Pick colors with hue and alpha controls.
Installation
bunx --bun shadcn@latest add https://kit.dev/r/color-picker.jsonpnpm dlx shadcn@latest add https://kit.dev/r/color-picker.jsonnpx shadcn@latest add https://kit.dev/r/color-picker.jsonyarn shadcn@latest add https://kit.dev/r/color-picker.json<Step>This component depends on Button. Install it first if you haven't already.</Step>
Install the following dependencies:
bun add @ark-ui/react lucide-reactpnpm add @ark-ui/react lucide-reactnpm install @ark-ui/react lucide-reactyarn add @ark-ui/react lucide-reactCopy and paste the following code into your project.
"use client";
import {
ColorPicker as ArkColorPicker,
parseColor as parseColorArk,
useColorPicker as useArkColorPicker,
useColorPickerContext as useArkColorPickerContext,
} from "@ark-ui/react/color-picker";
import { ark } from "@ark-ui/react/factory";
import { Portal } from "@ark-ui/react/portal";
import { CheckIcon, PipetteIcon } from "lucide-react";
import type React from "react";
import { cn } from "@/lib/utils";
import { Button, type ButtonProps } from "@/components/ui/button";
export const parseColor = parseColorArk;
export const useColorPicker = useArkColorPicker;
export const useColorPickerContext = useArkColorPickerContext;
export const ColorPickerContext = ArkColorPicker.Context;
export interface ColorPickerProps
extends Omit<
React.ComponentProps<typeof ArkColorPicker.Root>,
"defaultValue" | "value"
> {
/**
* The default value of the color picker.
*/
defaultValue?: string;
/**
* The value of the color picker.
*/
value?: string;
}
const colorPickerRootClassName = cn("group/color-picker", "flex w-fit gap-2");
export const ColorPicker = (props: ColorPickerProps) => {
const {
value,
defaultValue,
positioning = {
placement: "top-start",
},
lazyMount = true,
unmountOnExit = true,
className,
children,
...rest
} = props;
return (
<ArkColorPicker.Root
className={cn(colorPickerRootClassName, className)}
data-slot="color-picker"
defaultValue={defaultValue ? parseColor(defaultValue) : undefined}
lazyMount={lazyMount}
positioning={positioning}
unmountOnExit={unmountOnExit}
value={value === undefined ? undefined : parseColor(value)}
{...rest}
>
{children}
<ArkColorPicker.HiddenInput />
</ArkColorPicker.Root>
);
};
export const ColorPickerRootProvider = (
props: React.ComponentProps<typeof ArkColorPicker.RootProvider>
) => {
const {
lazyMount = true,
unmountOnExit = true,
className,
children,
...rest
} = props;
return (
<ArkColorPicker.RootProvider
className={cn(colorPickerRootClassName, className)}
data-slot="color-picker"
lazyMount={lazyMount}
unmountOnExit={unmountOnExit}
{...rest}
>
{children}
<ArkColorPicker.HiddenInput />
</ArkColorPicker.RootProvider>
);
};
export const ColorPickerLabel = (
props: React.ComponentProps<typeof ArkColorPicker.Label>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.Label
className={cn("font-medium text-sm", className)}
data-slot="color-picker-label"
{...rest}
/>
);
};
export const ColorPickerControl = (
props: React.ComponentProps<typeof ArkColorPicker.Control>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.Control
className={cn("flex flex-row items-center gap-2", className)}
data-slot="color-picker-control"
{...rest}
/>
);
};
export const ColorPickerTrigger = (
props: React.ComponentProps<typeof ArkColorPicker.Trigger>
) => <ArkColorPicker.Trigger data-slot="color-picker-trigger" {...props} />;
export const ColorPickerTransparencyGrid = (
props: React.ComponentProps<typeof ArkColorPicker.TransparencyGrid>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.TransparencyGrid
className={cn(
"size-full rounded-[calc(var(--radius-sm)-0.5px)]",
"bg-[linear-gradient(45deg,#e4e4e4_25%,transparent_25%),linear-gradient(-45deg,#e4e4e4_25%,transparent_25%),linear-gradient(45deg,transparent_75%,#e4e4e4_75%),linear-gradient(-45deg,transparent_75%,#e4e4e4_75%)]",
"bg-position-[0_0,0_4px,4px_-4px,-4px_0] bg-size-(--spacing(2))",
className
)}
{...rest}
/>
);
};
export const ColorPickerContent = (
props: React.ComponentProps<typeof ArkColorPicker.Content>
) => {
const { className, ...rest } = props;
return (
<Portal>
<ArkColorPicker.Positioner data-slot="color-picker-positioner">
<ArkColorPicker.Content
className={cn(
"[--space:--spacing(3)]",
"z-50",
"relative",
"w-full min-w-56",
"flex flex-col gap-4",
"p-(--space)",
"bg-popover",
"rounded-xl border shadow-lg/5",
"outline-none",
"origin-(--transform-origin)",
"data-[state=open]:fade-in-0 data-[state=open]:zoom-in-[98%] data-[state=open]:animate-in",
"data-[state=closed]:fade-out-0 data-[state=closed]:zoom-out-[98%] data-[state=closed]:animate-out",
"motion-reduce:animate-none!",
className
)}
data-slot="color-picker-content"
{...rest}
/>
</ArkColorPicker.Positioner>
</Portal>
);
};
export const ColorPickerView = (
props: React.ComponentProps<typeof ArkColorPicker.View>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.View
className={cn("relative flex size-full flex-1 flex-col gap-4", className)}
data-slot="color-picker-view"
{...rest}
/>
);
};
export const ColorPickerSlider = (
props: React.ComponentProps<typeof ArkColorPicker.ChannelSlider>
) => {
const { className, children, ...rest } = props;
return (
<ArkColorPicker.ChannelSlider
className={cn(
"relative",
"flex items-center",
"touch-none select-none",
"rounded-full border",
"data-[orientation=horizontal]:w-full",
"data-[orientation=vertical]:h-full data-[orientation=vertical]:min-h-40 data-[orientation=vertical]:w-auto data-[orientation=vertical]:flex-col",
"group-data-disabled/color-picker:pointer-events-none group-data-disabled/color-picker:cursor-not-allowed group-data-disabled/color-picker:opacity-64",
className
)}
data-slot="color-picker-channel-slider"
{...rest}
>
{children}
<ArkColorPicker.ChannelSliderTrack
className={cn(
"grow",
"rounded-full",
"select-none overflow-hidden",
"data-[orientation=horizontal]:h-2 data-[orientation=horizontal]:w-full",
"data-[orientation=vertical]:h-full data-[orientation=vertical]:w-2"
)}
data-slot="color-picker-channel-slider-track"
/>
<ArkColorPicker.ChannelSliderThumb
className={cn(
"relative shrink-0",
"size-4.5",
"-translate-1/2",
"rounded-full border-[3px] border-white shadow-[0_0_0_1px_rgba(0,0,0,0.1),inset_0_0_0_1px_rgba(0,0,0,0.1)]",
"outline-none ring-1 ring-border/64",
"origin-left data-[orientation=vertical]:origin-bottom"
)}
data-slot="color-picker-channel-slider-thumb"
/>
</ArkColorPicker.ChannelSlider>
);
};
interface ColorPickerEyeDropperTrigger
extends React.ComponentProps<typeof ArkColorPicker.EyeDropperTrigger>,
ButtonProps {}
export const ColorPickerEyeDropperTrigger = (
props: ColorPickerEyeDropperTrigger
) => {
const { variant = "outline", size = "icon-md", children, ...rest } = props;
return (
<ArkColorPicker.EyeDropperTrigger
data-slot="color-picker-eye-dropper"
{...rest}
asChild
>
<Button aria-label="Sample color" size={size} variant={variant}>
{children ?? <PipetteIcon aria-hidden="true" />}
</Button>
</ArkColorPicker.EyeDropperTrigger>
);
};
export const ColorPickerSwatchGroup = (
props: React.ComponentProps<typeof ArkColorPicker.SwatchGroup>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.SwatchGroup
className={cn("flex flex-wrap items-center gap-2", className)}
data-slot="color-picker-swatch-group"
{...rest}
/>
);
};
export const ColorPickerSwatchTrigger = (
props: React.ComponentProps<typeof ArkColorPicker.SwatchTrigger>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.SwatchTrigger
className={cn(
"relative",
"size-8",
"flex items-center justify-center",
"rounded-full",
"transition-[border-color,box-shadow] duration-100 ease-out will-change-transform",
"outline-none focus-visible:border-primary focus-visible:ring-[3px] focus-visible:ring-ring/32 focus-visible:ring-offset-2 focus-visible:ring-offset-background",
"data-disabled:pointer-events-none data-disabled:opacity-64",
"data-[state=checked]:shadow-sm/5 data-[state=checked]:ring-(--color) data-[state=checked]:ring-2",
"motion-reduce:transition-none!",
className
)}
data-slot="color-picker-swatch-trigger"
{...rest}
/>
);
};
export const ColorPickerSwatch = (
props: React.ComponentProps<typeof ArkColorPicker.Swatch>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.Swatch
className={cn(
"size-full",
"shrink-0",
"overflow-hidden",
"rounded-[inherit]",
"transition-transform duration-100 ease-out will-change-transform",
"not-[data-state=checked]:hover:scale-110",
"data-[state=checked]:scale-[0.8]",
"motion-reduce:transition-none!",
className
)}
data-slot="color-picker-swatch"
{...rest}
/>
);
};
export const ColorPickerSwatchIndicator = (
props: React.ComponentProps<typeof ArkColorPicker.SwatchIndicator>
) => {
const { className, children, ...rest } = props;
return (
<ArkColorPicker.SwatchIndicator
className={cn(
"absolute inset-0 z-10",
"flex items-center justify-center",
"text-white",
"pointer-events-none",
"zoom-in-5 animate-in blur-in-md",
"[&_svg]:size-1/2",
"motion-reduce:animate-none!",
className
)}
data-slot="color-picker-swatch-indicator"
{...rest}
>
{children ?? <CheckIcon aria-hidden="true" />}
</ArkColorPicker.SwatchIndicator>
);
};
export const ColorPickerValue = (
props: React.ComponentProps<typeof ArkColorPicker.ValueText>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.ValueText
className={cn("font-medium text-sm", className)}
data-slot="color-picker-value"
{...rest}
/>
);
};
export const ColorPickerValueSwatch = (
props: React.ComponentProps<typeof ArkColorPicker.ValueSwatch>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.ValueSwatch
className={cn(
"relative size-8 shrink-0",
"overflow-hidden",
"rounded-full border",
className
)}
data-slot="color-picker-value-swatch"
{...rest}
/>
);
};
interface ColorPickerAreaProps
extends React.ComponentProps<typeof ArkColorPicker.Area> {
/**
*
*/
showDots?: boolean;
}
export const ColorPickerArea = (props: ColorPickerAreaProps) => {
const { className, showDots = false, children, ...rest } = props;
return (
<ArkColorPicker.Area
className={cn(
"relative",
"aspect-square size-full",
"rounded-xl border",
"touch-none",
{
"after:pointer-events-none after:absolute after:inset-0 after:rounded-[inherit] after:bg-[radial-gradient(circle,#fff3_1px,#0000_1px)] after:bg-size-[8px_8px]":
showDots,
},
className
)}
data-slot="color-picker-area"
{...rest}
>
<ArkColorPicker.AreaBackground
className="size-full rounded-[inherit]"
data-slot="color-picker-area-background"
/>
{children}
</ArkColorPicker.Area>
);
};
export const ColorPickerAreaThumb = (
props: React.ComponentProps<typeof ArkColorPicker.AreaThumb>
) => {
const { className, ...rest } = props;
return (
<ArkColorPicker.AreaThumb
className={cn(
"size-4.5",
"rounded-full border-[3px] border-white shadow-[0_0_0_1px_rgba(0,0,0,0.1),inset_0_0_0_1px_rgba(0,0,0,0.1)]",
"outline-none ring-border/64",
"data-disabled:pointer-events-none data-disabled:opacity-64",
className
)}
data-slot="color-picker-area-thumb"
{...rest}
/>
);
};
export const ColorPickerInput = (
props: Partial<React.ComponentProps<typeof ArkColorPicker.ChannelInput>>
) => {
const { channel = "hex", ...rest } = props;
return (
<ArkColorPicker.ChannelInput
channel={channel}
data-slot="color-picker-input"
{...rest}
/>
);
};
export const ColorPickerSwatchPreview = (
props: React.ComponentProps<typeof ark.div>
) => {
const { className, ...rest } = props;
return (
<ark.div
className={cn(
"relative",
"size-8",
"shrink-0",
"rounded-full border",
"pointer-events-none overflow-hidden",
"group-data-[size=lg]/input-group:size-5",
"group-data-[size=md]/input-group:size-4",
"group-data-[size=sm]/input-group:size-3.5",
"group-data-disabled/color-input:opacity-64",
className
)}
data-slot="color-picker-input-swatch"
{...rest}
>
<ArkColorPicker.TransparencyGrid
className={cn(
"size-full rounded-[calc(var(--radius-sm)-0.5px)]",
"bg-[linear-gradient(45deg,#e4e4e4_25%,transparent_25%),linear-gradient(-45deg,#e4e4e4_25%,transparent_25%),linear-gradient(45deg,transparent_75%,#e4e4e4_75%),linear-gradient(-45deg,transparent_75%,#e4e4e4_75%)]",
"bg-position-[0_0,0_4px,4px_-4px,-4px_0] bg-size-(--spacing(2))"
)}
/>
<ArkColorPicker.ValueSwatch className="z-1 size-full" />
</ark.div>
);
};Update the import paths to match your project setup.
shadcn.io wraps Ark UI Color Picker. value / defaultValue on ColorPicker are strings (parsed with parseColor). useColorPicker takes Ark Color objects — use parseColor("#eb5e41"). Hidden input is baked into ColorPicker / ColorPickerRootProvider. lazyMount and unmountOnExit default to true (Ark: false). positioning.placement defaults to top-start.
useColorPicker is the machine hook for ColorPickerRootProvider. useColorPickerContext / ColorPickerContext is in-tree.
Root Provider
Pass machine options (defaultValue, format, inline, positioning, …) to useColorPicker(), not to the provider. Presence (lazyMount, unmountOnExit) can still be set on the provider.
Context
Open state
Control the popover with open and onOpenChange. { open, value }.
Inline
inline renders area, sliders, and swatches without a popover.
Modes
You can use multiple modes to build the color picker that fits your needs:
- Input for hex or channel editing
- Popover for area and slider selection
- Swatch picker for preset colors
- Area standalone component for color selection
- Slider for color adjustment
Input
Anatomy
ColorPicker
├── ColorPickerControl
│ └── InputGroup
│ ├── ColorPickerTrigger
│ │ └── ColorPickerSwatchPreview
│ └── ColorPickerInput
└── ColorPickerContent
├── ColorPickerArea
│ └── ColorPickerAreaThumb
└── ColorPickerView
└── ColorPickerSliderUsage
import {
ColorPicker,
ColorPickerInput,
} from "@/components/ui/color-picker";<ColorPicker>
<ColorPickerInput asChild channel="hex">
<Input />
</ColorPickerInput>
</ColorPicker>Controlled
Use the value and onValueChange props to programmatically control the color picker's state.
States
Invalid
Disabled
Examples
With Field
Channel Editing
With Swatch
Input with ColorPickerSwatchPreview showing the current color alongside the hex input.
With Popover
An input with trigger and popover content for area, hue, and alpha selection.
Compact
Inspired by Figma's color input.
Popover
Color picker with trigger and popover content.
Anatomy
ColorPicker
├── ColorPickerControl
│ └── ColorPickerTrigger
└── ColorPickerContent
├── ColorPickerArea
│ └── ColorPickerAreaThumb
├── ColorPickerView
│ ├── ColorPickerEyeDropperTrigger
│ └── ColorPickerSlider
│ └── ColorPickerTransparencyGrid
└── ColorPickerSwatchGroup
└── ColorPickerSwatchTrigger
└── ColorPickerSwatchUsage
import {
ColorPicker,
ColorPickerArea,
ColorPickerAreaThumb,
ColorPickerContent,
ColorPickerEyeDropperTrigger,
ColorPickerSlider,
ColorPickerTrigger,
ColorPickerTransparencyGrid,
ColorPickerView,
} from "@/components/ui/color-picker";<ColorPicker>
<ColorPickerTrigger />
<ColorPickerContent>
<ColorPickerArea>
<ColorPickerAreaThumb />
</ColorPickerArea>
<ColorPickerView>
<ColorPickerEyeDropperTrigger />
<ColorPickerSlider channel="hue" />
<ColorPickerSlider channel="alpha">
<ColorPickerTransparencyGrid />
</ColorPickerSlider>
</ColorPickerView>
</ColorPickerContent>
</ColorPicker>States
Disabled
Set disabled to prevent user interaction.
Examples
With Eye Dropper
With Channel Editing
Popover with area, sliders, and input fields for editing red, green, and blue values.
With Only Sliders
Popover with hue, saturation, lightness, and alpha sliders only, no color area.
With Swatch Picker
Popover with preset color swatches for quick selection.
Color Swatch Picker
Set inline on ColorPicker so swatches render without a popover.
Anatomy
ColorPicker
└── ColorPickerSwatchGroup
└── ColorPickerSwatchTrigger
└── ColorPickerSwatch
└── ColorPickerSwatchIndicatorUsage
import {
ColorPicker,
ColorPickerSwatchTrigger,
ColorPickerSwatchGroup,
ColorPickerSwatch,
ColorPickerSwatchIndicator,
} from "@/components/ui/color-picker";<ColorPicker>
<ColorPickerSwatchGroup>
<ColorPickerSwatchTrigger value="#0485F7">
<ColorPickerSwatch value="#0485F7">
<ColorPickerSwatchIndicator />
</ColorPickerSwatch>
</ColorPickerSwatchTrigger>
</ColorPickerSwatchGroup>
</ColorPicker>Controlled
Use the value and onValueChange props to programmatically control the swatch picker's state.
States
Disabled
Set disabled to prevent user interaction.
Examples
Custom Size
Customize swatch size using the size-* on ColorPickerSwatchTrigger.
Custom Radius
Override the default rounded style on ColorPickerSwatchTrigger using the rounded-* utility class.
Custom Indicator
Replace the default check icon with a custom indicator via the children of ColorPickerSwatchIndicator.
Area
Set inline on ColorPicker for a standalone color area.
Anatomy
ColorPicker
└── ColorPickerArea
└── ColorPickerAreaThumbUsage
import {
ColorPicker,
ColorPickerArea,
ColorPickerAreaThumb,
} from "@/components/ui/color-picker";<ColorPicker>
<ColorPickerArea>
<ColorPickerAreaThumb />
</ColorPickerArea>
</ColorPicker>Examples
Color Channels
With Dots
Slider
Set inline on ColorPicker for standalone sliders. Wrap multiple sliders in ColorPickerView.
Anatomy
ColorPicker
└── ColorPickerView
└── ColorPickerSlider
└── ColorPickerTransparencyGridUsage
import {
ColorPicker,
ColorPickerSlider,
} from "@/components/ui/color-picker";<ColorPicker>
<ColorPickerSlider channel="hue" />
</ColorPicker>Controlled
States
Disabled
Examples
Alpha Channel
HSL Channels
HSBA Channels
RGB Channels
Vertical
Custom spacing
Use [--space:--spacing("value")] on ColorPickerContent to adjust internal spacing.
Default spacing is --spacing(3).
You can use breakpoint utilities to change the internal spacing at different screen sizes.
md:[--space:--spacing(6)] lg:[--space:--spacing(8)]API Reference
shadcn.io wraps Ark UI Color Picker. Defaults below are shadcn.io values. lazyMount / unmountOnExit default to true (Ark: false). value / defaultValue on ColorPicker are CSS color strings. Ark useColorPicker uses Color from parseColor.
asChild merges props onto a single child element.
ColorPicker
Root. Renders a div. Hidden input is baked in.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Render the child element instead of a div. |
className | string | - | Class names on the root. |
closeOnSelect | boolean | false | Close the popover when a swatch is selected. |
defaultFormat | ColorFormat | "rgba" | Uncontrolled format. |
defaultOpen | boolean | - | Uncontrolled open state. |
defaultValue | string | "#000000" | Uncontrolled color string. |
disabled | boolean | - | Disable the picker. |
format | ColorFormat | - | Controlled format (hex, hexa, rgb, rgba, hsl, hsla, hsb, hsba, oklch). |
hideMode | "display-none" | "activity" | "display-none" | How to hide unmounted content. activity needs React 19+. |
id | string | - | Unique id for the machine. |
inline | boolean | false | Render without a popover. |
invalid | boolean | - | Invalid state. Also inherited from Field. |
lazyMount | boolean | true | Mount popover content on first open. |
name | string | - | Hidden input name. |
onFormatChange | (details: FormatChangeDetails) => void | - | Format changed. { format }. |
onOpenChange | (details: OpenChangeDetails) => void | - | Open state changed. { open, value }. |
onValueChange | (details: ValueChangeDetails) => void | - | Color changed. { value: Color, valueAsString: string }. |
onValueChangeEnd | (details: ValueChangeDetails) => void | - | Color change finished (pointer up). |
open | boolean | - | Controlled open state. |
positioning | PositioningOptions | { placement: "top-start" } | Popover position. |
readOnly | boolean | - | Focusable but not editable. |
required | boolean | - | Required for forms. |
unmountOnExit | boolean | true | Unmount popover after close animation. |
value | string | - | Controlled color string. |
| Attribute | Description |
|---|---|
data-slot | color-picker |
data-scope | color-picker |
data-part | root |
data-disabled | Present when disabled |
data-invalid | Present when invalid |
data-readonly | Present when read-only |
ColorPickerRootProvider
Takes the API from useColorPicker. Hidden input is baked in.
| Prop | Type | Default | Description |
|---|---|---|---|
value | UseColorPickerReturn | required | Return value of useColorPicker(). |
asChild | boolean | false | Render the child element instead of a div. |
className | string | - | Class names on the root. |
lazyMount | boolean | true | Presence: mount content on first open. |
unmountOnExit | boolean | true | Presence: unmount after close. |
Pass defaultValue: parseColor("#eb5e41"), format, inline, positioning, and other machine options to useColorPicker(), not to the provider.
ColorPickerLabel
Visible label. Renders a label. Prefer Field for form layouts.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the label. |
| Attribute | Description |
|---|---|
data-slot | color-picker-label |
data-scope | color-picker |
data-part | label |
ColorPickerTrigger
Opens the popover. Renders a button. Use asChild with InputGroupAddon or Button.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the trigger. |
| Attribute | Description |
|---|---|
data-slot | color-picker-trigger |
data-scope | color-picker |
data-part | trigger |
ColorPickerContent
Popover surface. Portals with a positioner. Renders a div.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the content. Set [--space:] here. |
| CSS variable | Default | Description |
|---|---|---|
--space | --spacing(3) | Padding and inner gap |
| Attribute | Description |
|---|---|
data-slot | color-picker-content |
data-scope | color-picker |
data-part | content |
data-state | "open" or "closed" |
ColorPickerControl
Row for input, trigger, and swatch preview. Renders a div.
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the control. |
ColorPickerView
Shows children only when its format matches the current format. Renders a div.
| Prop | Type | Default | Description |
|---|---|---|---|
format | ColorFormat | - | Format this view is for. |
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the view. |
ColorPickerArea
2D selection. Bakes AreaBackground. Renders a div.
| Prop | Type | Default | Description |
|---|---|---|---|
showDots | boolean | false | shadcn.io: overlay a dotted grid. |
xChannel / yChannel | ColorChannel | - | Axes for the area. |
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the area. |
ColorPickerAreaThumb
Thumb on the area. role="slider" with aria-roledescription="2d slider".
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the thumb. |
ColorPickerSlider
Channel slider. Bakes track and thumb. channel is required.
| Prop | Type | Default | Description |
|---|---|---|---|
channel | ColorChannel | required | Channel to edit. |
orientation | "horizontal" | "vertical" | "horizontal" | Slider axis. |
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the slider. |
ColorPickerTransparencyGrid
Checkerboard for alpha. Place as a child of ColorPickerSlider for the alpha channel.
| Prop | Type | Default | Description |
|---|---|---|---|
size | string | - | Grid cell size. |
asChild | boolean | false | Merge onto a single child. |
className | string | - | Class names on the grid. |
ColorPickerEyeDropperTrigger
Always asChild onto Button. Uses the EyeDropper API when the browser supports it. Default aria-label is "Sample color".
| Prop | Type | Default | Description |
|---|---|---|---|
variant | Button variant | "outline" | Button variant. |
size | Button size | "icon-md" | Button size. |
children | ReactNode | pipette icon | Replace the icon. |
className | string | - | Class names on the trigger. |
ColorPickerInput
Channel input (ChannelInput). Use asChild with Input or InputGroupInput. Default channel is "hex".
| Prop | Type | Default | Description |
|---|---|---|---|
channel | ExtendedColorChannel | "hex" | Channel or "hex" / "css". |
asChild | boolean | false | Merge onto a single child. |
ColorPickerSwatchPreview
shadcn.io compact current-color swatch (transparency grid + value swatch). Use in an input group addon.
ColorPickerSwatchGroup / ColorPickerSwatchTrigger / ColorPickerSwatch / ColorPickerSwatchIndicator
Preset swatches. ColorPickerSwatchTrigger value is a CSS color string. Indicator defaults to a check icon (aria-hidden).
ColorPickerValue / ColorPickerValueSwatch
Formatted text (ValueText) and current-color swatch (ValueSwatch).
parseColor
Parses a CSS color string into an Ark Color. Required for useColorPicker({ defaultValue }).
parseColor("#eb5e41").toString("hex");useColorPicker
Creates the API for ColorPickerRootProvider. defaultValue / value are Color, not strings.
const colorPicker = useColorPicker({ defaultValue: parseColor("#eb5e41") });
colorPicker.setValue("#10B981");ColorPickerContext / useColorPickerContext
Render-prop or hook access. Use inside ColorPicker or ColorPickerRootProvider.
| Property | Type | Description |
|---|---|---|
value | Color | Current color object. |
valueAsString | string | Formatted color string. |
open | boolean | Whether the popover is open. |
inline | boolean | Whether the picker is inline. |
dragging | boolean | Whether a thumb is dragging. |
format | ColorFormat | Current format. |
setValue | (value: string | Color) => void | Set the color. |
setOpen | (open: boolean) => void | Open or close the popover. |
getChannelValue | (channel: ColorChannel) => string | Channel as string. |
setChannelValue | (channel: ColorChannel, value: number) => void | Set one channel. |
ColorPickerContext children: (context) => ReactNode.
Accessibility
The area thumb is a 2D slider (aria-roledescription="2d slider"). Channel sliders are sliders with aria-valuetext for the channel. The eye dropper is an icon button (aria-label="Sample color"). Pair inputs with Field. Decorative check and pipette icons are aria-hidden.
Keyboard support
| Key | Description |
|---|---|
Tab | Move between trigger, inputs, area thumb, sliders, swatches, and eye dropper. |
Enter / Space | Open the popover from the trigger, or select a focused swatch. |
Escape | Close the popover. On area/slider, stop propagation so the popover can close. |
| Arrow keys | Move the area thumb (2D) or the focused channel slider. Respects RTL on sliders. |
PageUp / PageDown | Larger step on the area or slider. |
Home / End | Min / max of the focused channel slider. |
Shift + Arrow | Larger step (native event step multiplier). |