ColorField
A numeric input component for editing individual color channels, with optional increment/decrement buttons and a color swatch preview.
Preview
Source code
tsx
import "internationalized-color/css";
import { colorSpaces } from "@urcolor/core";
import { ColorField, useColor } from "@urcolor/react";
export default function ColorFieldHSL() {
const { color, setColor } = useColor("hsl(210, 80%, 50%)");
const channels = colorSpaces["hsl"]?.channels ?? [];
return (
<div className="flex items-start gap-4">
<div className="flex flex-1 flex-wrap gap-2">
{channels.map((ch) => (
<div key={ch.key} className="flex min-w-[80px] flex-1 flex-col gap-1">
<label
htmlFor={`field-${ch.key}`}
className="text-xs font-semibold text-[var(--vp-c-text-2)]"
>
{ch.label}
</label>
<ColorField.Root
value={color}
onValueChange={setColor}
colorSpace="hsl"
channel={ch.key}
className="
flex items-center overflow-hidden rounded-md border
border-[var(--vp-c-divider)] bg-[var(--vp-c-bg)]
"
>
<ColorField.Decrement
className="
flex size-8 shrink-0 cursor-pointer items-center justify-center
border-r border-none border-r-[var(--vp-c-divider)] bg-transparent
text-lg leading-none text-[var(--vp-c-text-2)] select-none
hover:not-disabled:bg-[var(--vp-c-bg-soft)]
hover:not-disabled:text-[var(--vp-c-text-1)]
disabled:cursor-default disabled:opacity-30
"
>
−
</ColorField.Decrement>
<ColorField.Input
id={`field-${ch.key}`}
className="
w-0 min-w-0 flex-1 border-none bg-transparent px-0.5 py-1
text-center font-mono text-[13px] text-[var(--vp-c-text-1)]
outline-none
"
/>
<ColorField.Increment
className="
flex size-8 shrink-0 cursor-pointer items-center justify-center
border-l border-none border-l-[var(--vp-c-divider)] bg-transparent
text-lg leading-none text-[var(--vp-c-text-2)] select-none
hover:not-disabled:bg-[var(--vp-c-bg-soft)]
hover:not-disabled:text-[var(--vp-c-text-1)]
disabled:cursor-default disabled:opacity-30
"
>
+
</ColorField.Increment>
</ColorField.Root>
</div>
))}
</div>
</div>
);
}Anatomy
tsx
<ColorField.Root>
<ColorField.Decrement />
<ColorField.Input />
<ColorField.Increment />
</ColorField.Root>
<ColorField.Swatch />Examples
Hex Input
Source code
tsx
import "internationalized-color/css";
import { ColorField, useColor } from "@urcolor/react";
export default function ColorFieldHex() {
const { color, setColor } = useColor("hsl(210, 80%, 50%)");
return (
<div className="flex items-center gap-3">
<ColorField.Root
value={color}
onValueChange={setColor}
colorSpace="hex"
channel="hex"
format="hex"
className="
flex h-8 items-center overflow-hidden rounded-md border
border-[var(--vp-c-divider)] bg-[var(--vp-c-bg)] px-3
"
>
<ColorField.Input
className="
min-w-0 flex-1 border-none bg-transparent px-3 py-1.5 font-mono
text-[13px] text-[var(--vp-c-text-1)] outline-none
"
/>
</ColorField.Root>
</div>
);
}HSL Channel Fields
HSL channel inputs with increment/decrement buttons.
Source code
tsx
import "internationalized-color/css";
import { colorSpaces } from "@urcolor/core";
import { ColorField, useColor } from "@urcolor/react";
export default function ColorFieldHSL() {
const { color, setColor } = useColor("hsl(210, 80%, 50%)");
const channels = colorSpaces["hsl"]?.channels ?? [];
return (
<div className="flex items-start gap-4">
<div className="flex flex-1 flex-wrap gap-2">
{channels.map((ch) => (
<div key={ch.key} className="flex min-w-[80px] flex-1 flex-col gap-1">
<label
htmlFor={`field-${ch.key}`}
className="text-xs font-semibold text-[var(--vp-c-text-2)]"
>
{ch.label}
</label>
<ColorField.Root
value={color}
onValueChange={setColor}
colorSpace="hsl"
channel={ch.key}
className="
flex items-center overflow-hidden rounded-md border
border-[var(--vp-c-divider)] bg-[var(--vp-c-bg)]
"
>
<ColorField.Decrement
className="
flex size-8 shrink-0 cursor-pointer items-center justify-center
border-r border-none border-r-[var(--vp-c-divider)] bg-transparent
text-lg leading-none text-[var(--vp-c-text-2)] select-none
hover:not-disabled:bg-[var(--vp-c-bg-soft)]
hover:not-disabled:text-[var(--vp-c-text-1)]
disabled:cursor-default disabled:opacity-30
"
>
−
</ColorField.Decrement>
<ColorField.Input
id={`field-${ch.key}`}
className="
w-0 min-w-0 flex-1 border-none bg-transparent px-0.5 py-1
text-center font-mono text-[13px] text-[var(--vp-c-text-1)]
outline-none
"
/>
<ColorField.Increment
className="
flex size-8 shrink-0 cursor-pointer items-center justify-center
border-l border-none border-l-[var(--vp-c-divider)] bg-transparent
text-lg leading-none text-[var(--vp-c-text-2)] select-none
hover:not-disabled:bg-[var(--vp-c-bg-soft)]
hover:not-disabled:text-[var(--vp-c-text-1)]
disabled:cursor-default disabled:opacity-30
"
>
+
</ColorField.Increment>
</ColorField.Root>
</div>
))}
</div>
</div>
);
}API Reference
ColorField.Root
The root container that manages field state and color channel binding.
| Prop | Type | Default | Description |
|---|---|---|---|
value | Color | string | null | — | Controlled color value. |
defaultValue | Color | string | null | — | Initial color when uncontrolled. |
colorSpace | string | 'hsl' | Color space mode (e.g. 'hsl', 'oklch', 'hex'). |
channel | string | 'h' | Channel to control (e.g. 'h', 's', 'l', 'hex'). |
format | 'number' | 'degree' | 'percentage' | 'hex' | Auto | Display format. Auto-derived from channel config if omitted. |
min | number | Auto | Minimum value. Auto-derived from channel config. |
max | number | Auto | Maximum value. Auto-derived from channel config. |
step | number | Auto | Arrow key step increment. Auto-derived from channel config. |
disabled | boolean | false | Disables interaction. |
readOnly | boolean | false | Makes the field read-only. |
onValueChange | (color: Color) => void | — | Called when color changes. |
onValueCommit | (color: Color) => void | — | Called when interaction ends (blur or Enter). |
ColorField.Input
The text input element for entering color channel values.
ColorField.Increment
Button to increment the color field value. Auto-disabled at maximum.
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | false | Disables the button. |
ColorField.Decrement
Button to decrement the color field value. Auto-disabled at minimum.
| Prop | Type | Default | Description |
|---|---|---|---|
disabled | boolean | false | Disables the button. |
ColorField.Swatch
Displays a color preview swatch with automatic checkerboard background.
| Prop | Type | Default | Description |
|---|---|---|---|
value | Color | string | null | — | The color value to display. |
alpha | boolean | false | When true, reflects the color's alpha channel. |
checkerSize | number | 16 | The checkerboard tile size in pixels. |
Accessibility
ColorField provides a spinbutton interface for precise numeric color channel editing.
Keyboard Navigation
| Key | Action |
|---|---|
| Arrow Up | Increase by one step |
| Arrow Down | Decrease by one step |
| Page Up | Increase by 10x step |
| Page Down | Decrease by 10x step |
| Home | Jump to minimum |
| End | Jump to maximum |
| Enter | Commit current value |