Skip to main content

Swatch

Info:Controls html svelte astro Success: coverage 25/25

A color chip pairing a colored dot with an optional label and value.

Live demo

live · @xoji/astro

Swatch

Named colors

Hot pink#ff0099 Sky#0ea5e9 Emerald#22c55e Amber#f59e0b

Palette rail

Pickable palette

Each chip is a real button; click or focus and press Enter. The chosen one rings in the accent.

Selected: Sky

Color details

Hover or focus a chip to read its color across models, parsed and reformatted by the engine.

Hot pinkhex#ff0099rgbrgb(255 0 153)hslhsl(324 100% 50%)oklchoklch(0.653 0.2684 354.7) Tealhex#00b9c3rgbrgb(0 185 195)hslhsl(183 100% 38%)oklchoklch(0.714 0.1215 201.8) Violet 80%hex#7c3aedccrgbrgb(124 58 237 / 0.8)hslhsl(262 83% 58% / 0.8)oklchoklch(0.541 0.2466 293 / 0.8)

Sizes

Small Medium Large

Swatch is the smallest way to show a color and say what it is. A filled dot beside an optional name and an optional value in mono; the shape every label + value + dot row and palette rail is built from.

The color it shows is data, not theme: it comes in on the color prop and is painted straight onto the dot as an inline fill, so a swatch can carry any color a user hands it, including one nowhere in the current theme. Its own chrome is the derived part: the dot's hairline border, the label and value type, the corner radius all read from the same tokens the rest of the UI does, so the chip frames a foreign color in the theme's own voice. A thin border keeps even a near-background color legible against the surface. The size prop steps the whole chip with the surrounding type from sm to lg.

When to use

How this component composes with the rest of the set.

Stack named swatches in a Stack for a legend: each a label + value + dot row.
Set bare swatches (color only) in a tight Cluster for a palette rail.
Pair a swatch with a Badge or Text in a Cluster to annotate a color in running UI.

Props

7 props, straight from the manifest.

PropTypeDefaultBindingsDescription
color string
html svelte astro
The color the dot displays; arbitrary user data, painted as an inline fill. Any CSS color works, but it is not a theme token.
label string
html svelte astro
An optional name for the color, shown beside the dot.
value string
html svelte astro
An optional raw value (e.g. a hex string) shown after the label in mono.
size SwatchSize
sm md lg
md
html svelte astro
The chip size, stepping with the type scale: `sm`, `md`, or `lg`.
interactive boolean false
html svelte astro
For pickable palettes: render the chip as a `<button>` that emits a `select` event (carrying `{ color, label, value }`) on click, Enter, or Space. Off by default, so a swatch stays a passive display chip.
selected boolean false
html svelte astro
The chosen state for an interactive chip; rings the dot in the accent and sets `aria-pressed`. Controlled: the consumer owns it and flips it in response to `select`, so a single-choice rail stays authoritative.
details boolean false
html svelte astro
Show a popover on hover and focus listing the color across `hex` / `rgb` / `hsl` / `oklch`, parsed and reformatted by the engine; a built-in way to read a color without leaving the chip.

Appearance

Sizes

sm

.xoji-swatch--sm

A compact chip for dense palette rails.

md

default
.xoji-swatch

The default chip, sized with body text.

lg

.xoji-swatch--lg

A prominent chip for a featured color.

States

selected

.xoji-swatch--selected .xoji-swatch__dot

An interactive chip in its chosen state: the dot ringed in the accent, aria-pressed set.

focus-visible

.xoji-swatch--interactive:focus-visible

An interactive chip focused by keyboard; a ring picks it out for the next selection.

Anatomy

The named parts that make up the component, with their selectors.

swatch

.xoji-swatch

The chip root: a row laying out the dot, label, and value.

dot

.xoji-swatch__dot

The color chip itself, filled with the inline color data and ringed by a hairline border so a near-background color still reads.

--line-2 --border-thin --radius-sm

label

.xoji-swatch__label

The optional color name, set in body text.

--fg-1 --text-sm --leading-tight

value

.xoji-swatch__value

The optional raw value (e.g. a hex string), set in mono and dimmed.

--fg-2 --font-mono --text-xs --leading-tight

details

.xoji-swatch__details

The optional hover/focus popover listing the color across models; an overlay card whose chrome is derived even though the values inside are the swatch's own color, parsed and reformatted.

--surface-overlay --surface-overlay-border --radius-md --elevation-2 --space-1 --space-2 --space-8

detail-model

.xoji-swatch__detail-model

A color-model name (hex, rgb, …) in the details popover, set in body type.

--fg-2 --font-sans --text-xs --leading-tight

detail-value

.xoji-swatch__detail-value

A formatted color value in the details popover, set in mono.

--fg-1 --font-mono --text-xs --leading-tight

Tokens & coverage

What the component consumes, checked live against what the algorithm produces.

Success:fully covered 25/25 consumed tokens produced default register: 276 tokens

Live coverage check against the xoji-default register (derive(xojiDefault, { anchors })coverComponent(manifest, register)). Every token this component consumes must be a key the algorithm produces.

--accent --bg-1 --border-normal --border-thick --border-thin --duration-fast --ease-standard --elevation-2 --fg-1 --fg-2 --font-mono --font-sans --leading-tight --line-2 --radius-md --radius-sm --ring --space-1 --space-2 --space-8 --surface-overlay --surface-overlay-border --text-lg --text-sm --text-xs

Accessibility

The dot is marked aria-hidden. Color alone carries no meaning to assistive tech, so the label and value text carry the identity.
Always provide a label (and ideally a value) when the color is meaningful, so the chip is announced by name, not by an invisible swatch.
An interactive chip is a real <button>, so Enter and Space activate it and Tab reaches it for free; when it carries no visible label it borrows its value or color as an aria-label.
selected reflects to aria-pressed, so a picked chip announces its chosen state to assistive tech, not just its accent ring. Each chip is an independent toggle; if a rail is single-choice, the consumer enforces that by clearing the others on select.
A details chip is keyboard-reachable even when it isn't interactive: it takes tabindex and points aria-describedby at the popover, so the color readout is available on focus, not hover alone.

Code

Named swatches and sizes

Labeled chips with values, plus the bare dot across the three sizes.

<xoji-swatch color="#ff0099" label="Hot pink" value="#ff0099"></xoji-swatch>
<xoji-swatch color="#22c55e" label="Success"></xoji-swatch>

<xoji-swatch color="#0ea5e9" size="sm"></xoji-swatch>
<xoji-swatch color="#0ea5e9" size="lg" label="Sky" value="#0ea5e9"></xoji-swatch>
<script lang="ts">
	import { Swatch } from "@xoji/svelte";
</script>

<Swatch color="#ff0099" label="Hot pink" value="#ff0099" />
<Swatch color="#22c55e" label="Success" />
---
import Swatch from "@xoji/astro/Swatch.astro";
---

<Swatch color="#ff0099" label="Hot pink" value="#ff0099" />
<Swatch color="#22c55e" label="Success" />

Pickable chips and color details

An interactive chip emits select and shows a selected ring; a details chip reveals the color across models on hover and focus.

<xoji-swatch color="#0ea5e9" label="Sky" interactive selected></xoji-swatch>
<xoji-swatch color="#22c55e" label="Emerald" interactive></xoji-swatch>

<xoji-swatch color="#ff0099" label="Hot pink" details></xoji-swatch>

<script>
	document.querySelector("xoji-swatch[interactive]")
		.addEventListener("select", (e) => console.log(e.detail));
</script>
<script lang="ts">
	import { Swatch } from "@xoji/svelte";
	let picked = $state("#0ea5e9");
</script>

<Swatch color="#0ea5e9" label="Sky" interactive selected={picked === "#0ea5e9"}
	onselect={(e) => (picked = e.detail.color)} />
<Swatch color="#ff0099" label="Hot pink" details />
---
import Swatch from "@xoji/astro/Swatch.astro";
---

<Swatch color="#0ea5e9" label="Sky" interactive selected />
<Swatch color="#ff0099" label="Hot pink" details />