ColorField
Popover-wrapped colour selector — a pill trigger with a circular icon-swatch
and a label that opens a ColorPicker in a dialog popover. This is the
reusable field-level control for colour inputs; the picker itself is the panel.
import { ColorField } from '@tangible/ui';
Interactive docs and examples: ColorField in Storybook.
ColorField props
| Prop | Type | Default | Description |
|---|---|---|---|
align? |
"center" | "end" | "start" |
'start' |
Popover alignment. |
alpha? |
boolean |
true |
|
aria-label? |
string |
||
aria-labelledby? |
string |
Identifies the element (or elements) that labels the current element. | |
className? |
string |
||
defaultFormat? |
"hex" | "hsl" | "hwb" | "oklch" | "rgb" |
'hex' |
|
defaultOpen? |
boolean |
||
defaultValue? |
string |
'#000000' |
Uncontrolled initial value. |
disabled? |
boolean |
||
dynamic? |
boolean |
false |
Dynamic-data treatment — a neutral swatch with a bolt icon, for values bound to dynamic sources rather than a fixed colour. |
format? |
"hex" | "hsl" | "hwb" | "oklch" | "rgb" |
||
formats? |
ColorFormat[] |
all |
Formats offered in the picker's format selector, in order. |
gradient? |
boolean |
false |
Offer a Gradient tab beside the solid picker. The value may then also be a CSS gradient string; the active tab is derived from the value, and switching tabs converts it. Solid → gradient is benign (a two-stop gradient of the colour, or the session's last gradient restored); gradient → solid is DESTRUCTIVE — the gradient collapses to its first stop's colour (recoverable only while the popover stays open). |
icon? |
IconName |
'system/edit-small' ('system/bolt-fill' when `dynamic`) |
Override the swatch icon. |
id? |
string |
||
label? |
React.ReactNode |
Human-readable name shown on the trigger (e.g. "Primary"). Falls back to the current value / variable name when omitted. | |
labels? |
ColorFieldLabels |
Override any user-facing string for i18n (picker strings + trigger). |
|
onFormatChange? |
(format: ColorFormat) => void |
||
onOpenChange? |
(open: boolean) => void |
||
onValueChange? |
(value: string) => void |
||
open? |
boolean |
||
showLabel? |
boolean |
true |
Show the label text beside the swatch. |
showSwatch? |
boolean |
true |
Show the icon-swatch before the label. Opt out for a text-only trigger (a dense settings row where the value text is the affordance). Hiding the swatch also hides the dynamic bolt and any icon — the accessible name still carries the dynamic state. With both this and showLabel off the trigger would be empty, so the label is kept and a dev warning fires. |
side? |
"bottom" | "left" | "right" | "top" |
'bottom' |
Popover side relative to the trigger. |
size? |
"lg" | "md" | "sm" |
'md' |
|
value? |
string |
Controlled value — a CSS colour, a var(--x[, fallback]) reference, or (with gradient) a CSS gradient string. |
|
variant? |
"bare" | "field" |
'field' |
Trigger chrome. bare removes the field box and sizes the swatch to the control height (an IconButton-shaped tile), keeping the focus ring and the swatch's own edge. Composes with showLabel={false} for a swatch-only tile, or with a label for a chrome-less swatch + text row. |
Also accepts the standard attributes of ButtonHTMLAttributes (data-*, aria-*, event handlers), passed to the element it renders.
Examples
-
Labelled rows: Compose with
Fieldfor row labels —Field.Controlwiresaria-labelledby(andid) onto the trigger. Pass a human-readablelabel(e.g. "Primary") for the pill text instead of the raw value. Setdynamicfor values bound to dynamic data — a neutral swatch with a bolt icon. The swatch icon is contrast-picked so it stays legible on any colour. -
Label only:
showSwatch={false}drops the icon-swatch for a text-only trigger. Note thedynamicbolt goes with it — the accessible name still says "(dynamic)". Turning both slots off is guarded (the label is kept and a dev warning fires) — see theshowSwatchprop docs. -
Bare (swatch tiles):
variant="bare"drops the field box so the swatch is the control, sized to the control height like anIconButtonof the samesize(a baresmtile is 32px, clearing the 24px target minimum). Built for colour-ladder strips and swatch grids; pair withshowLabel={false}for tiles, or keep the label for a chrome-less swatch + text row. -
Gradient mode (Solid | Gradient tabs): With
gradient, the popover gains Solid | Gradient tabs. The active tab derives from the value; switching converts it (solid → two-stop gradient of itself, gradient → first stop). The trigger swatch renders the gradient. -
Gradient mode, solid value: The same field starting from a solid value — the Solid tab is active until the user switches, which converts the colour into a two-stop gradient of itself.
Other stories: ColorField (popover), Swatch only, Alpha values, var() value, Gradient swatch triggers (interactive page).
Component API tokens: shared with ColorPicker.