ColorField
A color input: a native color picker and a hex field under one legend, with optional suggested swatches.
ColorFieldExample.tsx
import { ColorField } from "@/components/ColorField";
export function ColorFieldExample() {
return (
<ColorField
label="Action color"
hint="Buttons and links use it."
defaultValue="#b37500"
swatches={[
{ value: "#b37500", name: "Gold 600" },
{ value: "#1c87a5", name: "Cyan 500" },
{ value: "#5b3fa6", name: "Violet 600" },
{ value: "#2a8556", name: "Green 600" },
]}
/>
);
}Examples
Hex only
Controlled
Stored value: #5b3fa6
Invalid hex
Disabled
Props
Any native prop not listed here goes to the root element unchanged.
Native <fieldset> props (className, id, ref and the rest) go to the fieldset. Hex is a template type for "#…" strings; the value is always lowercase "#rrggbb". The hex field reads "#rgb", "#rrggbb", or either without "#", in any case.
| Prop | Type | Default | Description |
|---|---|---|---|
label | string | — | The visible legend. It names the group and the color picker. Required by the type. |
hint | ReactNode | — | Help text under the legend, read as the group's description. |
value | Hex | — | Controlled value, "#rrggbb". Pair with onValueChange. |
defaultValue | Hex | "#000000" | Uncontrolled initial value. |
onValueChange | (value: Hex) => void | — | Called with each new valid value, lowercase "#rrggbb": from the picker, a swatch, or hex text as soon as it parses. |
swatches | readonly { value: Hex; name: string }[] | — | Suggested colors, shown as buttons named by name, with the hex as their description. The one matching the value is pressed. |
swatchesLabel | string | "Suggested colors" | The swatch group's accessible name. |
disabled | boolean | false | Disables the whole fieldset: the picker, the hex field and the swatches. |
Component tokens
| Token | Copy | Description | Aliases | Light | Dark | Preview |
|---|---|---|---|---|---|---|
--component-color-field-gap | Space between the legend, hint, controls and swatches, and between swatches. | space.stack.sm | 0.5remfrom space.2 | 0.5remfrom space.2 | ||
--component-color-field-swatch-size | Swatch button size: at least 24px (WCAG 2.5.8). | size.icon.lg | 1.5remfrom size.6 | 1.5remfrom size.6 | ||
--component-color-field-swatch-border | Swatch outline, so a swatch close to the surface still has a 3:1 boundary. | color.border.strong | #6d7e90from color.gray.500 | #818b9efrom color.slate.400 | ||
--component-color-field-swatch-radius | Swatch corner radius. | radius.control | 4pxfrom radius.4 | 4pxfrom radius.4 | ||
--component-color-field-picker-size | The color picker's size: the height of the small hex field beside it. | size.control.sm | 2remfrom size.8 | 2remfrom size.8 | ||
--component-color-field-picker-border | Color picker outline. | color.border.strong | #6d7e90from color.gray.500 | #818b9efrom color.slate.400 | ||
--component-color-field-picker-radius | Color picker corner radius. | radius.control | 4pxfrom radius.4 | 4pxfrom radius.4 | ||
--component-color-field-legend-text | The legend. | color.text.default | #17202bfrom color.gray.900 | #fffffffrom color.gray.0 |
Accessibility
- A <fieldset> whose <legend> names the group, and the native color picker inside it through aria-labelledby. The hex field is a TextField labelled "Hex", so the group reads as, for example, "Action color, group", then "Hex, edit text".
- The value is always shown as hex text, so it never relies on color alone.
- Hex text is applied as soon as it's a valid color. If it isn't valid when the field loses focus, the field shows an error with a warning icon, is marked invalid, and the last valid color stays.
- Each swatch is a toggle button named by its swatch name, with the hex as its description and both in a tooltip. The one matching the value is pressed, shown by a ring around it, outside a gap, so it reads on light and dark swatches alike, and not by color. In forced colors the pressed swatch gets a thick system-color border, apart from the focus outline.
- Swatches are 24px (WCAG 2.5.8), and swatch and picker outlines are checked to 3:1 against the surfaces in both themes, so a color close to the page still has a visible edge. In forced colors the colors themselves stay, with system-color outlines.
| Key | Action |
|---|---|
| Tab | Moves to the color picker, then the hex field, then each swatch. |
| Enter / Space | On the picker, opens the browser's color dialog. On a swatch, sets its color. |