Skip to content

HySwatch ​

Usage examples on this page are written for Lit / plain HTML (<hy-swatch>). The same component ships as HySwatch in @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, the hy-icon idiom).

Accessibility: your part ​

  • Give every swatch a label that 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. An inset label 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) ​

html
<hy-swatch
  value="500"
  color="#4A90E2"
  label="500"
  label-placement="inset"
  aria-label="Brand 500"
></hy-swatch>

Non-color cell (dimension rung) ​

html
<hy-swatch value="spacing.spa3" label="12px">
  <div class="rung-preview"></div>
</hy-swatch>

API ​

Properties ​

PropertyAttributeTypeDefaultDescription
valuevaluestring''Identity reported to the group on selection. Required when selectable.
colorcolorstring''Convenience fill for the sample square. Any CSS color or var(--hy-…).
labellabelstring''Label text (e.g. a stop number or px value).
labelPlacementlabel-placement'caption' | 'inset''caption'Where the label sits: caption (below) or inset (on the fill).
selectedselectedbooleanfalseWhether this cell is selected. Managed by the group; reflected for styling.
disableddisabledbooleanfalseDisables 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).
decorativedecorativebooleanfalseMarks 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.
tooltiptooltipstring''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 ​

SlotDescription
defaultCustom sample content (gradient, image, dimension preview). Overrides the color fill.

CSS Parts ​

PartDescription
baseThe cell wrapper (carries hover / selected / focus chrome).
sampleThe visual sample square.
labelThe inset label rendered over the sample.
captionThe 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.

PropertyDefaultDescription
--hy-swatch-border-default-restvar(--hy-border-default-rest)Cell border on hover.
--hy-swatch-border-brand-restvar(--hy-border-brand-rest)Cell border when selected.
--hy-swatch-background-surface-subtlevar(--hy-background-surface-subtle)Cell background on hover.
--hy-swatch-background-brand-tint-subtlevar(--hy-background-brand-tint-subtle)Cell background when selected.
--hy-swatch-sample-border-default-restvar(--hy-border-default-rest)Border framing the sample square.
--hy-swatch-foreground-subtle-restvar(--hy-foreground-subtle-rest)Caption text color.
--hy-swatch-radius-container-smvar(--hy-radius-container-sm)Cell and sample corner radius.
--hy-swatch-gap-layout-2xsvar(--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-sizenoneMaximum sample size (default none; a wrapping group sets it to its size preset, so a long caption widens the cell, not the square).

Built with Lit. Documented with VitePress.