ColorSwatchPicker
A set of mutually exclusive color options built from native <input type="radio"> controls sharing one grouping name, rendered as a role="radiogroup" host wrapping ColorSwatchPicker.Swatch instances styled from each input's own :checked state.
Shown on every issue carrying this label.
View code
let picked = { value: "#3b82f6", name: "Blue" };
<div mix={[vstack({ gap: 2, align: "start" }), maxIs("22rem")]}>
<Label id="preview-label-color">Label color</Label>
<ColorSwatchPicker
aria-labelledby="preview-label-color"
name="labelColor"
mix={[
flexWrap(),
on<HTMLDivElement, "change">("change", (event) => {
let input = event.target;
if (!(input instanceof HTMLInputElement)) return;
picked = LABEL_COLORS.find((color) => color.value === input.value) ?? picked;
void handle.update();
}),
]}
>
{LABEL_COLORS.map((color) => (
<ColorSwatchPicker.Swatch
key={color.value}
value={color.value}
aria-label={color.name}
shape="rounded"
checked={color.value === picked.value}
parts={{ input: [ariaChecked()] }}
/>
))}
</ColorSwatchPicker>
<Description id="preview-label-color-hint">
Shown on every issue carrying this label.
</Description>
<div mix={[hstack({ gap: 2, align: "center" })]}>
<ColorSwatch value={picked.value} shape="rounded" size="sm" />
<span mix={[text("sm")]}>
<span mix={[weight("medium")]}>needs-triage</span>{" "}
<span mix={[fg("neutral")]}>· {picked.name}</span>
</span>
</div>
</div>Installation
An ordinary dependency: install it, import the theme once, and import the component where it is used.
npm add @sdxc/uiimport "@sdxc/ui/theme.css";Usage
import { ColorSwatchPicker } from "@sdxc/ui";Renders the group host: a role="radiogroup" <div> laying its
ColorSwatchPicker.Swatch options out in a wrapping row, sharing its
name through context so each option defaults to the group's own identifier.
Composition
The parts the component publishes, each a static property of the host.
ColorSwatchPickerColorSwatchPicker.SwatchRenders a single option: a hidden<input type="radio">paired with a ColorSwatch indicator, styled throughprecededBy()since a bare element-first selector here would serialize as a declaration, not a match.
Examples
<ColorSwatchPicker aria-label={t("form.brandColor.label")}>
<ColorSwatchPicker.Swatch value="#f97316" aria-label={t("color.orange")} shape="circle" size="lg" />
<ColorSwatchPicker.Swatch value="#a855f7" aria-label={t("color.purple")} shape="circle" size="lg" />
</ColorSwatchPicker>Props
Read from the component's own types, so every prop, every default and every allowed value is listed.
| Prop | Type | Description |
|---|---|---|
name? | string | Native grouping name shared by every ColorSwatchPicker.Swatch nested inside. Defaults to the group's own stable instance id when omitted. |
Also accepts everything in TagProps<"div">.
ColorSwatchPicker.Swatch
| Prop | Type | Description |
|---|---|---|
value | string | The color this option submits and previews, already resolved to a literal CSS color value — the same value ColorSwatch paints its indicator with and submits with the enclosing form. |
"aria-label" | string | Accessible name announced for this option in place of visible text — a color's name, for instance. Required, since the indicator identifies the option to assistive technology through this text alone. |
name? | string | Native grouping name for this option's underlying input. Defaults to the name provided by the nearest ancestor ColorSwatchPicker — set this only to opt a single option out of its group's shared name. |
shape? | ColorSwatch.Shape | The indicator's shape variant, forwarded to ColorSwatch. |
size? | ColorSwatch.Size | The indicator's size variant, forwarded to ColorSwatch. |
defaultChecked? | boolean | Whether this option starts selected, for a form that never tracks selection itself. |
checked? | boolean | Whether this option is selected, for a form that tracks selection itself. |
disabled? | boolean | Whether this option is inert and excluded from the group's tab order. |
required? | boolean | Marks the enclosing native radio group as requiring one option selected. |
parts? | {
/** Additional mixin(s) applied to the hidden native `<input type="radio">`. */
input?: TagProps<"input">["mix"];
/** Additional mixin(s) applied to the {@link ColorSwatch} indicator. */
indicator?: TagProps<"span">["mix"];
} | Per-part styling for the option's hidden input and its ColorSwatch indicator, layered after each part's own built-in styling. The mix prop styles the option's outer <label> host. |
Also accepts everything in Omit<TagProps<"label">, "children" | "aria-label">.