Color pickers

Values with no name: ColorPicker for a solid, GradientPicker for stops, ImagePicker for a file — each its own provider-driven layout. The trigger is yours.

Demo

The sheet’s three sets on one Component select: the pickers, the smaller cards, the sliders, the six dropdown triggers, and the modal. Most controls pick a composition, not a prop.

Saved

Component
Picker
Value format
Swatch size
import { ColorPicker } from "@/components/application/color-picker/color-picker"; <ColorPicker.Provider defaultValue="#2563EB"> <ColorPicker.Dialog> <ColorPicker /> <ColorPicker.SavedColors colors={SAVED_COLORS} /> </ColorPicker.Dialog> </ColorPicker.Provider>

The value format only moves on a remount

defaultColorFormat seats the provider’s initial state and is never read again, so the demo remounts the provider when you change it. In a real screen the format select inside the picker is what changes it, and that select is already wired.

Contextual demo

A picker sits behind a swatch, and the trigger that opens it is the part the kit does not ship — so it gets a screen.

The trigger and the popover are application markup

The Figma sheet draws six trigger types with an open and a closed state each. None of them ships. The Demo’s Dropdown trigger subject composes all six, the preview builds one into a real screen, and both are React Aria’s DialogTrigger and Popover with application markup — which is what you would write, and the largest gap on this page.

The family

Three pickers, one card, and their parts. The card, the provider, and every part hang off ColorPicker as static members.

The components in this family, with their descriptions and import paths
ComponentDescriptionImport from
ColorPickerThe solid picker: a saturation and brightness area, an eyedropper, hue and alpha sliders, and a format select beside the value input. Carries the family’s card, provider, and parts as static members.@/​components/​application/​color-picker/​color-picker
GradientPickerThe gradient picker: a draggable 2D gradient area, a type dropdown, a reverse button, a stop track, and the editable stop list.@/​components/​application/​gradient-picker/​gradient-picker
ImagePickerThe image picker: a drop zone that draws the file to a canvas, a fill-mode dropdown, a rotate button, and seven adjustment sliders.@/​components/​application/​image-picker/​image-picker
ColorPicker.SavedColorsA labelled swatch row with an optional Add button. Inside a provider it is already wired: the current color is marked selected, and clicking a swatch sets it.@/​components/​application/​color-picker/​color-picker
SwatchItemOne round swatch, at 16px or 20px. Selectable only inside a React Aria ColorSwatchPicker, which SavedColors supplies.@/​components/​application/​color-picker/​color-picker
InputCellThe input shell the value fields are built from: a ringed box with a corner radius per position, so a row of them reads as one input group.@/​components/​application/​color-picker/​color-picker

Built from

Six kit pieces across three directories; four have their own docs page.

Component
Where it’s used here
SelectThe value format picker, at size="sm" in a fixed 80px box.
DropdownThe gradient type and the image fill mode, both behind a link-gray button with a 12px chevron.
Button and ButtonUtilityThe eyedropper, Add, reverse, rotate, and remove-stop controls.
FileTriggerThe click-to-upload path in the image picker’s drop zone.

The three pickers

Each is an all-in-one layout with no props: what it edits comes from the provider around it. All three are live.

Saved

ColorPicker in ColorPicker.Dialog. Add saves the current color

Stops

GradientPicker, in the same card

or drag and drop

Exposure
Contrast
Saturation
Temperature
Tint
Highlights
Shadows
ImagePicker, in the same card

The card’s padding is the kit’s

ColorPicker.Dialog is the family’s only card, and since 2026-08-22 it sets gap-4 p-5 itself, so the three cells above pass nothing. The 20px gutter and the 16px rhythm are the sheet’s, read off its Solid color symbol, and were measured on these cards that day in Chromium against a production build.

The three match the sheet exactly

Measured at 1440px: 320 by 492, 320 by 524, and 320 by 616. The sheet’s symbols are 536, 636, and 660 tall. Every difference is something the kit does not render pre-assembled: a 32px tab strip and its 12px gap on all three, and on the gradient card a 52px saved row plus its 16px gap. 492 plus 44 is 536; 524 plus 44 plus 68 is 636; 616 plus 44 is 660. Nothing else is off by a pixel. The strip itself is the kit’s own underline Tabs — the sheet’s “Horizontal tabs” instance — and the Demo’s Tabbed picker subject composes the full symbol live, three providers around one card; the symbol’s close X belongs to the popover chrome, where the Dropdown trigger subject wires it.

Rebuilt from parts

The sheet’s smaller cards are the solid picker taken apart and reassembled in a narrower box, from the exported members.

Minimal picker at 312px: eyedropper, two sliders, one value input

Saved

Saved swatches at 248px: omitting onAdd hides the Add button

Gray

Saved swatches at 208px: size sm, 16px swatches on the same component

Three cards, three of the sheet’s sizes

Dialog knows one card, the full one, at rounded-2xl, p-5, and gap-4. The sheet draws its smaller cards at a 12px radius with their own padding, so each cell above passes rounded-xl and the rest by hand: p-4 on the 312 and 248px cards, and on the 208px card p-3 gap-3 with size="sm", whose 16px swatches on an 8px gap put eight in its 184px of content width exactly, as the 20px ones do in the 248px card’s 216.
ColorPicker.HueSlider, on its own
ColorPicker.AlphaSlider, on its own

Saved gradients

ColorPicker.SavedColors given gradients: plain buttons, and inert without an onSelect

What is composed, and what stays unbuilt

The palette picker, the large color preview card, all six dropdown triggers, and the modal are composed live in the Demo above, from kit parts plus React Aria — the kit still ships none of them as components. What stays unbuilt is smaller: the brand and gray cards’ source note and their Docs and Reset footer, which SavedColors has no slot for. Listed row by row on the Code tab.

Value formats

The format select and the value input read the same provider. All five formats are live, each in its own provider.

Format hex
Format rgb
Format css
Format hsl
Format hsb

A sixth model lives in the gradient picker

The sheet’s _Color inputs family has six members. Five are the formats above. The sixth is a gradient stop row: a position field, a color field, an alpha field, and a remove button, which the kit renders only inside GradientPicker.StopList and never on its own.

Stops

GradientPicker.StopList: the sixth model, in context

States

Almost every state belongs to a part, not a picker. Click, tab, and drag the cells: they are real controls.

Saved

Swatches: click to select, tab for the focus ring. Either ring is 2px, 3px out
Input cell: the ring turns brand on focus within
Thumb: grab it, or tab to it and use the arrow keys

Stops

Remove: disabled while only two stops are left
SwatchItem size: sm is 16px, md is 20px. SavedColors passes the same prop through, md by default

Two states are not shown here

The drop zone’s drop-target ring needs a file dragged over it, and the eyedropper is only rendered where the browser has the EyeDropper API. Both are described on the Code tab rather than faked here.