Built on Vercel’s UI SDK 0.1.0-beta.1. Its API may change.
Color picker
A color picker on Vercel's UI SDK with a saturation area, hue and alpha sliders, typed CSS colors, presets and an eyedropper.
- Form components
- 15 parts
- 11 examples
@tabler/icons-react@ui-sdk/core@ui-sdk/react
pnpm dlx shadcn@latest add https://hextaui.com/r/ui-sdk-color-picker.jsonAdds the component, the HextaUI theme tokens and any HextaUI components it depends on.
Add the theme tokens to your global CSS, if you haven’t yet.
Install the dependencies.
pnpm add @ui-sdk/react@0.1.0-beta.1 @ui-sdk/core@0.1.0-beta.1 @tabler/icons-react cnCopy and paste the following code into your project.
components/ui/ui-sdk-color-picker.tsx Update the import paths to match your project setup.
UI SDK adds a little CSS of its own in a cascade layer named ui-sdk. Declare that layer at the top of your global stylesheet, above the Tailwind import, so your classes win over it.
The value is a CSS color string. Every part edits the same color, so use only the parts you need. ColorPickerArea and ColorPickerSlider render their thumb for you. Name the picker with aria-label, or with the label of a field around it.
Render the parts in place, without a popover, for a settings page or a sidebar.
A slider with channel="alpha" edits opacity. Its track and the swatch draw a checkerboard under the color, so a see-through color reads as see-through.
With space="oklch", add ColorPickerAreaCanvas to paint the area. Colors outside the screen’s gamut stay clear, and a thumb dragged there settles on the closest color inside when you let go.
ColorPickerSwatches is one tab stop with arrow keys between presets, and a preset stays selected however the value is written. ColorPickerChannelInput edits one channel as a number. The eyedropper hides itself in browsers that can’t pick from the screen.
Set orientation="vertical" on a slider to stand it beside the area.
onValueChange runs on every step of a drag, and onValueCommit once when it ends, so save there. A controller from createColorPickerController() sets the color from anywhere.
A hidden input submits the value under name, and a form reset goes back to defaultValue.
A disabled picker can’t be focused or changed, and submits nothing.
With readOnly, the thumbs stay focusable and the value is submitted, but drags, keys and typing leave the color alone.
UI SDK reads the direction from the page, so the area, the sliders and the arrow keys mirror. The inputs pick their own direction, so a hex value still reads left to right.
| Key | Action |
|---|---|
| ←→↑↓ | Moves a thumb one step. On the area, left and right move across, up and down move up and down. |
| Shift + arrow | Moves ten steps. |
| Page UpPage Down | Moves a tenth of the range, up the area or along a slider. |
| HomeEnd | Moves to the start or the end. |
| Enter | Reads the text in the input, or picks the focused preset. |
| Esc | Puts the input’s text back to the value, or closes the popover. |
No WAI-ARIA pattern covers a color picker, so UI SDK builds it from ones that do. The picker is a group. The area’s thumb and each slider thumb are sliders, and the area’s thumb names both of its channels, like “Saturation 76%, Brightness 96%”. The presets are a listbox, and each preset and the swatch are named by their color, like “vivid blue”.
The trigger in the popover example says the current color in its name. Thumbs grow while you drag only when motion is allowed, and the checkerboard, rings and focus outlines switch to system colors in forced colors mode.
Each part wraps the UI SDK part of the same name and accepts all of its props, including render and a className that can be a function of the part’s state.
| Prop | Type | Default |
|---|---|---|
value | string | – |
defaultValue | string | "black" |
onValueChangeRuns on every step of a drag, a key press, a typed color or a preset. | (value: string, details: ChangeDetails) => void | – |
onValueCommitRuns once when a drag, key or typed color ends. | (value: string, details: ChangeDetails) => void | – |
spaceWhich channels the parts edit. | "hsv" | "hsl" | "srgb" | "oklch" | "hsv" |
formatHow the value is written. Hex for hsv, the space’s own CSS syntax otherwise. | ColorFormat | – |
gamut | "srgb" | "p3" | false | "srgb" |
disabled | boolean | false |
readOnly | boolean | false |
required | boolean | false |
name | string | – |
form | string | – |
controllerFrom createColorPickerController(). | ColorPickerController | – |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="color-picker" | Target the root in CSS. |
data-disabled | Present when disabled. |
data-readonly | Present when read-only. |
data-required | Present when required. |
data-out-of-gamut | Present on every part while a drag holds a color outside the gamut. |
--color-picker-color | The color as CSS. Thumbs and swatches fill with it. |
| Prop | Type | Default |
|---|---|---|
xThe channel across. Saturation, red or chroma, by space. | ColorChannel | – |
yThe channel up. Brightness, lightness or green, by space. | ColorChannel | – |
children | ReactNode | <ColorPickerAreaThumb /> |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="color-picker-area" | Target the area in CSS. |
--color-area-background | The gradients that draw the area. Unset where a canvas paints it. |
--color-picker-radius | The area’s corner radius. Set by ColorPickerContent so its corners are concentric. |
| Attribute | Description |
|---|---|
data-slot="color-picker-area-thumb" | Target the thumb in CSS. |
--area-x | Where the thumb is across the area, from 0 to 1. |
--area-y | Where the thumb is up the area, from 0 to 1. |
| Prop | Type | Default |
|---|---|---|
channelHue, or blue in sRGB, by default. | ColorChannel | – |
orientation | "horizontal" | "vertical" | "horizontal" |
children | ReactNode | <ColorPickerSliderThumb /> |
render | ReactElement | (props, state) => ReactElement | <div> |
| Attribute | Description |
|---|---|
data-slot="color-picker-slider" | Target the slider in CSS. |
data-channel | The channel it edits, like hue or alpha. |
data-orientation | horizontal or vertical. |
--color-slider-background | A gradient through the channel. |
| Prop | Type | Default |
|---|---|---|
channelThe channel to edit, in the units people read it in. | ColorChannel | – |
render | ReactElement | (props, state) => ReactElement | <input> |
| Prop | Type | Default |
|---|---|---|
valueRequired. The preset’s color. | string | – |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribute | Description |
|---|---|
data-slot="color-picker-swatch-item" | Target presets in CSS. |
data-selected | Present while the value is this preset’s color. |
| Prop | Type | Default |
|---|---|---|
children | ReactNode | <IconColorPicker /> |
render | ReactElement | (props, state) => ReactElement | <button> |
| Attribute | Description |
|---|---|
data-unsupported | Present where the browser has no EyeDropper. The button is hidden then. |
ColorPickerPopover, ColorPickerTrigger and ColorPickerContent wrap the UI SDK popover. The content opens in the browser’s top layer, so it needs no portal.
| Prop | Type | Default |
|---|---|---|
side | "top" | "bottom" | "left" | "right" | "start" | "end" | "bottom" |
align | "start" | "center" | "end" | "start" |
sideOffset | number | 6 |
| Attribute | Description |
|---|---|
data-slot="popover-content" | Set by UI SDK on the popup. Target it in CSS. |
data-starting-style | Present while the popup animates in. |
data-ending-style | Present while the popup animates out. |
- CalendarA date grid for single, range and multiple selection, with sliding months, range previews and touch-sized days.
- CheckboxA checkbox whose check draws in, with indeterminate parents, groups and labels that share its hover.
- ComboboxA filterable select with chips, groups and async results, in a popup that resizes as you type.
- Date pickerA button that opens a calendar in a popover, or a bottom sheet on phones, for single dates and ranges.
- FieldLabels, descriptions and errors wired to their control, with validation states and layouts for forms.
- InputA text input with three sizes, invalid and read-only states, native validation styling and a 16px touch font so phones never zoom in.