ColorSwatchPicker
A single-select grid of color swatches. The user picks one with the pointer or the keyboard; the selected swatch carries an accent ring set off by a gap, so it reads on any hue — including the accent itself.
Basic
Compose ColorSwatchPicker.Root (which owns the value) with one ColorSwatchPicker.Item per color. Give each item a color and a colorName — the name becomes the swatch's accessible label — and name the group with aria-label. Drive it with value / onValueChange, or omit them and pass defaultValue to let it own its state.
"use client";
import { ColorSwatchPicker } from "@stridge/noctis";
import { useState } from "react";
const SWATCHES = [
{ name: "Blue", value: "oklch(0.6 0.14 248)" },
{ name: "Teal", value: "oklch(0.62 0.12 195)" },
{ name: "Green", value: "oklch(0.62 0.15 150)" },
{ name: "Amber", value: "oklch(0.66 0.14 75)" },
{ name: "Rose", value: "oklch(0.58 0.18 18)" },
{ name: "Violet", value: "oklch(0.56 0.18 305)" },
];
export default function ColorSwatchBasic() {
const [value, setValue] = useState(SWATCHES[0].value);
return (
<ColorSwatchPicker.Root aria-label="Accent color" value={value} onValueChange={setValue}>
{SWATCHES.map((swatch) => (
<ColorSwatchPicker.Item key={swatch.name} color={swatch.value} colorName={swatch.name} />
))}
</ColorSwatchPicker.Root>
);
}
Sizes & rounding
size sets the edge length of every swatch — xs, sm (the 24px default), md, or lg. rounding sets the corners — control (follows the global radius knob, the default), sharp, soft, or full for circles.
"use client";
import { ColorSwatchPicker } from "@stridge/noctis";
const SWATCHES = [
{ name: "Blue", value: "oklch(0.6 0.14 248)" },
{ name: "Green", value: "oklch(0.62 0.15 150)" },
{ name: "Rose", value: "oklch(0.58 0.18 18)" },
];
export default function ColorSwatchSizesAndRounding() {
return (
<div className="flex flex-col gap-5">
<ColorSwatchPicker.Root aria-label="Small swatches" size="sm" defaultValue={SWATCHES[0].value}>
{SWATCHES.map((swatch) => (
<ColorSwatchPicker.Item key={swatch.name} color={swatch.value} colorName={swatch.name} />
))}
</ColorSwatchPicker.Root>
<ColorSwatchPicker.Root aria-label="Large round swatches" size="lg" rounding="full" defaultValue={SWATCHES[0].value}>
{SWATCHES.map((swatch) => (
<ColorSwatchPicker.Item key={swatch.name} color={swatch.value} colorName={swatch.name} />
))}
</ColorSwatchPicker.Root>
</div>
);
}
Anatomy
Compose the picker from its two parts. ColorSwatchPicker.Root is a Base UI RadioGroup, so selection, roving focus, and arrow-key navigation come for free.
ColorSwatchPicker.Root— the grid; owns the selected value (value/onValueChange, or uncontrolleddefaultValue) and the sharedsizeandrounding. Disable the whole group withdisabled; name it witharia-label.ColorSwatchPicker.Item— one swatch. Pass itscolor(any CSS color) and acolorNamefor the accessible label; itsvaluedefaults to thecolor.
Every rendered part carries a data-slot (noctis-color-swatch-picker on the grid, noctis-color-swatch-picker-item on each swatch, noctis-color-swatch on a standalone swatch) for host-side styling — pair it with the Base UI radio state attributes (data-checked, data-disabled).
Keyboard
| Key | Action |
|---|---|
| Tab | Move focus into the group, landing on the selected swatch (or the first). |
| ← / → / ↑ / ↓ | Move between swatches and select, wrapping at the ends. Arrows mirror under RTL. |
| Space | Select the focused swatch. |
Design tokens
Generated from the component's declaration — the same graph that mints the CSS, so a variable name or its resolution default can't drift. The minted tokens are the public override seam: set one on any ancestor and every swatch grid in that region retunes — e.g. .compact { --noctis-color-swatch-picker-gap: 0.25rem; } tightens the grid beneath it. Knobs that aren't minted are reached through the part's data-slot. See Customization for the full override ladder and Tokens for the whole graph.
API reference
Generated from the component's types — every prop, type, default, and description comes straight from the source. Each part gets its own table; the Root forwards the Base UI RadioGroup props it owns selection through. Expand a row for the full type and description.