Skip to content

Inputs

SwatchGroup

Single-choice color picker made of round swatches. Preset swatches follow the theme; custom ones take any CSS color.

<script>
  import { SwatchGroup } from "@codeatlasdev/ui";
  let preset = $state("ocean");
</script>

<SwatchGroup
  aria-label="Accent"
  bind:value={preset}
  items={[{ value: "ocean" }, { value: "violet" }, { value: "emerald" }]}
/>

Each item paints from the theme preset named by its value, so the swatch always matches the palette. Give an item a color to paint it with any CSS color instead; its value is then free-form. Leave value empty for “none selected”, for example while a custom color is active. The selected swatch shows a check mark.

On touch screens (pointer: coarse) each swatch grows to the 44px touch target, so neighbouring hit areas never overlap.

Accessibility. The group is a radiogroup and every swatch a radio with aria-checked. The group has no visible heading, so pass aria-label; each swatch is named by its label, falling back to value, so give custom colors a readable label (“Blue”, not “#2563eb”). Arrow keys move focus between enabled swatches and Tab leaves the group. The selected state does not rely on color alone: it adds a check mark and a ring, and both survive forced-colors mode.

#049

Theme presets

Swatches without a color paint from the preset named by their value.

value: ocean

Reference #049 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { SwatchGroup } from '@codeatlasdev/ui';

  let preset = $state('ocean');
</script>

<div class="col">
  <SwatchGroup
    aria-label="Accent"
    bind:value={preset}
    items={[
      { value: 'ocean' },
      { value: 'violet' },
      { value: 'emerald' },
      { value: 'rose' },
      { value: 'amber' },
    ]}
  />
  <p class="out">value: {preset}</p>
</div>

<style>
  .col {
    display: flex;
    flex-direction: column;
    gap: var(--ca-space-3);
  }

  .out {
    margin: 0;
    font-size: var(--ca-font-size-caption);
    color: var(--ca-text-secondary);
  }
</style>
#048

Custom colors

Any CSS color, a small size and a disabled swatch.

value: #2563eb

Reference #048 · Pick in the gallery

Code
svelte
<script lang="ts">
  import { SwatchGroup } from '@codeatlasdev/ui';

  let color = $state('#2563eb');
</script>

<div class="col">
  <SwatchGroup
    size="sm"
    aria-label="Label color"
    bind:value={color}
    items={[
      { value: '#2563eb', label: 'Blue', color: '#2563eb' },
      { value: '#16a34a', label: 'Green', color: '#16a34a' },
      { value: '#dc2626', label: 'Red', color: '#dc2626' },
      { value: '#9333ea', label: 'Purple', color: '#9333ea', disabled: true },
    ]}
  />
  <p class="out">value: {color}</p>
</div>

<style>
  .col {
    display: flex;
    flex-direction: column;
    gap: var(--ca-space-3);
  }

  .out {
    margin: 0;
    font-size: var(--ca-font-size-caption);
    color: var(--ca-text-secondary);
  }
</style>

Props

PropTypeDefaultDescription
valuestring''Bindable selected item value. Empty means none selected.
itemsSwatchItem[]–{ value, label?, color?, disabled? }. Without `color` the swatch paints from the theme preset named by `value`; `label` is the accessible name and falls back to `value`.
size'sm' | 'md''md'Swatch diameter.
disabledbooleanfalseDisables every swatch.
aria-labelstring–Accessible name of the group.
classstring–Extra classes on the root.
onchange(value: string) => void–Called when the user picks a different swatch.