HySwatch
Usage examples on this page are written for Lit / plain HTML (
<hy-swatch>). The same component ships asHySwatchin@whitespaceux/harmony-react(native React 19), with typed wrappers for Angular, Solid, Svelte, and Vue. The API reference below applies to all frameworks.
Used inside <hy-swatch-group> — it only means something as part of it.
A single selectable cell inside an hy-swatch-group.
hy-swatch is content-agnostic — it renders a sample (a color fill via the color attribute, or arbitrary default-slot content such as a gradient, image, or a dimension preview) plus a label. It has no knowledge of color math, ramps, or tokens; the parent group owns selection state, ARIA roles, roving tabindex, and keyboard interaction. Selection is shown by the cell's ring (border + background tint), not by color alone.
Label placement
caption(default) — label sits below the sample. Serves dimension/size rungs.inset— label sits centered on the fill, with an auto-contrast treatment (mix-blend) so it stays legible on any color. Serves color ramps.
Used on its own, a swatch is presentational. Selection behavior only exists inside hy-swatch-group, and so does the interactive chrome: the pointer cursor and hover ring appear only on a cell the group has given a role (single / multiple mode). In selection-mode="none" and standalone the cell is display-only — no hover, no selection ring.
Intrinsic size
The sample has a size of its own (--hy-swatch-size, 2.5rem by default; the group sets it per size): a floor it never goes under, which is also its rendered size wherever nothing stretches it. Without the floor a shrink-wrapped swatch — a centered flex item, inline-block, a table cell — collapsed to its borders. Inside a numeric-columns group the track sizes the sample both ways and the group lifts the floor (sets the hook to 0px), so a strip fits every stop in a narrow row.
When not to use
- People need any color, not one from a set:
hy-color-picker.
Accessibility: built in
- A dev-mode warning fires when a color-only swatch has no name, unless it is
decorative(hidden from assistive technology, thehy-iconidiom).
Accessibility: your part
- Give every swatch a
labelthat names the choice. A colored square alone names nothing to a screen reader or to someone who cannot tell the colors apart. - Keep
label-placement="caption"when the fills vary. Aninsetlabel can lose contrast against its fill. - A swatch whose color is already named by the text beside it, such as the color cell of a picker row: mark it
decorative, so the name isn't read twice.
Examples
Color cell (inset label)
<hy-swatch
value="500"
color="#4A90E2"
label="500"
label-placement="inset"
aria-label="Brand 500"
></hy-swatch>Non-color cell (dimension rung)
<hy-swatch value="spacing.spa3" label="12px">
<div class="rung-preview"></div>
</hy-swatch>API
Properties
| Property | Attribute | Type | Default | Description |
|---|---|---|---|---|
value | value | string | '' | Identity reported to the group on selection. Required when selectable. |
color | color | string | '' | Convenience fill for the sample square. Any CSS color or var(--hy-…). |
label | label | string | '' | Label text (e.g. a stop number or px value). |
labelPlacement | label-placement | 'caption' | 'inset' | 'caption' | Where the label sits: caption (below) or inset (on the fill). |
selected | selected | boolean | false | Whether this cell is selected. Managed by the group; reflected for styling. |
disabled | disabled | boolean | false | Disables the cell, removing it from selection and keyboard navigation. A disabled cell dims itself, except inside a disabled hy-swatch-group, which dims once for all its cells (every one aria-disabled there). |
decorative | decorative | boolean | false | Marks the swatch as purely decorative: the cell is hidden from assistive technology (aria-hidden on the base) and the WCAG 1.4.1 accessible-name warning is skipped. For a swatch whose meaning is carried by adjacent text — a picker option row's color cell, where the row's label names the option. Never for a swatch that is the only thing naming a color. |
tooltip | tooltip | string | '' | Hover/focus tooltip text — e.g. the resolved value (#d4d4d4). When set, the cell is wrapped in an hy-tooltip so the value surfaces on hover without a permanent on-screen readout. Empty = no tooltip. The cell stays the swatch host, so a wrapping hy-swatch-group's grid/selection is unaffected. |
Slots
| Slot | Description |
|---|---|
default | Custom sample content (gradient, image, dimension preview). Overrides the color fill. |
CSS Parts
| Part | Description |
|---|---|
base | The cell wrapper (carries hover / selected / focus chrome). |
sample | The visual sample square. |
label | The inset label rendered over the sample. |
caption | The caption text element below the sample. |
CSS Custom Properties
The documented hooks. Every override hook the component reads — one per token it paints — is listed in @whitespaceux/harmony/theme-api.json, and @whitespaceux/harmony/component-bindings.json (the Harmony MCP get-bindings tool) says which part and state each one paints.
| Property | Default | Description |
|---|---|---|
--hy-swatch-border-default-rest | var(--hy-border-default-rest) | Cell border on hover. |
--hy-swatch-border-brand-rest | var(--hy-border-brand-rest) | Cell border when selected. |
--hy-swatch-background-surface-subtle | var(--hy-background-surface-subtle) | Cell background on hover. |
--hy-swatch-background-brand-tint-subtle | var(--hy-background-brand-tint-subtle) | Cell background when selected. |
--hy-swatch-sample-border-default-rest | var(--hy-border-default-rest) | Border framing the sample square. |
--hy-swatch-foreground-subtle-rest | var(--hy-foreground-subtle-rest) | Caption text color. |
--hy-swatch-radius-container-sm | var(--hy-radius-container-sm) | Cell and sample corner radius. |
--hy-swatch-gap-layout-2xs | var(--hy-gap-layout-2xs) | Internal gap and padding. |
--hy-swatch-size | — | Minimum sample size (default 2.5rem; the group sets it per size, and to 0 under a numeric columns). |
--hy-swatch-max-size | none | Maximum sample size (default none; a wrapping group sets it to its size preset, so a long caption widens the cell, not the square). |