# Color swatch picker

A set of colors to pick one from, such as saved colors or colors to try, in rows that wrap.

Block: `smbk-color-swatch-picker`. Status: experimental. Figma: the Figma file, https://www.figma.com/community/file/1688324308358870630. Desktop and mobile: differ by presentation only.

## Options

| Axis | Values | Default | Meaning |
|---|---|---|---|
| `shape` | `square`, `round` | `square` | Square swatches, or dots. |
| `size` | `md`, `sm` | `md` | A 32 px item holding a 24 px swatch, or a 24 px item holding a 16 px one. |

Parts: `smbk-color-swatch-picker__item`

## Markup

```html
<div
  role="listbox"
  aria-orientation="horizontal"
  aria-label="Brand color"
  class="smbk-color-swatch-picker smbk-color-swatch-picker--shape-square smbk-color-swatch-picker--size-md"
>
  <div
    role="option"
    aria-selected="false"
    aria-label="Alert red"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(243, 67, 54, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Ember"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(250, 131, 73, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Sun"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(223, 206, 100, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Leaf"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(84, 184, 91, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Forest"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(3, 122, 31, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Sky"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(127, 160, 255, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="true"
    aria-label="Brand blue"
    tabindex="0"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(59, 92, 227, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Navy"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(33, 53, 131, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Brick"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(165, 29, 23, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Stone"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(124, 134, 146, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="Ink"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(17, 18, 19, 1)"></span></span>
  </div>
  <div
    role="option"
    aria-selected="false"
    aria-label="White"
    tabindex="-1"
    class="smbk-color-swatch-picker__item"
  >
    <span
      aria-hidden="true"
      class="smbk-color-swatch smbk-color-swatch--size-md smbk-color-swatch--shape-square"
    ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(255, 255, 255, 1)"></span></span>
  </div>
</div>
```

## React

```tsx
import { ColorSwatchPicker } from './design-system/components/color-swatch-picker/color-swatch-picker.js';

<ColorSwatchPicker shape="square" size="md" colors={[{ color: "#f34336", name: "Alert red" }, { color: "#fa8349", name: "Ember" }, { color: "#dfce64", name: "Sun" }, { color: "#54b85b", name: "Leaf" }, { color: "#037a1f", name: "Forest" }, { color: "#7fa0ff", name: "Sky" }, { color: "#3b5ce3", name: "Brand blue" }, { color: "#213583", name: "Navy" }, { color: "#a51d17", name: "Brick" }, { color: "#7c8692", name: "Stone" }, { color: "#111213", name: "Ink" }, { color: "#ffffff", name: "White" }]} defaultValue="#3b5ce3" aria-label="Brand color" />
```

## Stylesheet

```css
/* smbk-color-swatch-picker — Color swatch picker. Figma "Color swatch picker" 7408:540 and its
 * "ColorSwatchPickerItem" 7408:295.
 * Rows of items that wrap, the extra small inline step apart both ways. Each item is a color swatch
 * (smbk-color-swatch) inside the extra small inset, so a ring drawn inside the item's edge leaves a gap round
 * the swatch: the chosen item's ring is the inverse border color, a shape as well as a color, so "chosen" is
 * never told by color alone; the item with keyboard focus draws the ring in the focus color instead. Hover
 * lays the hover surface behind the swatch; a disabled item is dimmed. */

.smbk-color-swatch-picker {
  display: flex;
  flex-wrap: wrap;
  gap: var(--smbk-space-inline-xs);
  outline: none;
}

.smbk-color-swatch-picker__item {
  display: inline-flex;
  flex-shrink: 0;
  box-sizing: border-box;
  padding: var(--smbk-space-inset-xs);
  border-radius: var(--smbk-radius-container-sm);
  cursor: pointer;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}

@media (hover: hover) {
  .smbk-color-swatch-picker__item:hover {
    background: var(--smbk-color-surface-hover);
  }
}

.smbk-color-swatch-picker__item[aria-selected="true"] {
  box-shadow: inset 0 0 0 var(--smbk-border-width-2) var(--smbk-color-border-inverse);
}

.smbk-color-swatch-picker__item:focus-visible {
  box-shadow: inset 0 0 0 var(--smbk-border-width-2) var(--smbk-color-border-focus);
}

.smbk-color-swatch-picker__item[aria-disabled="true"] {
  opacity: var(--smbk-opacity-disabled);
  cursor: not-allowed;
}

@media (hover: hover) {
  .smbk-color-swatch-picker__item[aria-disabled="true"]:hover {
    background: none;
  }
}

/* ---- small: a 24 px item; its square corner is the control's medium one ---- */

.smbk-color-swatch-picker--size-sm .smbk-color-swatch-picker__item {
  border-radius: var(--smbk-radius-control-md);
}

/* Round: dots in round items. Two classes, so it wins over the small size's corner. */
.smbk-color-swatch-picker.smbk-color-swatch-picker--shape-round .smbk-color-swatch-picker__item {
  border-radius: var(--smbk-radius-full);
}

/* ---- touch: every color takes an invisible press area ----
   On a touch screen an invisible area, centred on each color, takes the press out to the comfortable target where it
   can, but only halfway into the gap between the colors, so in rows this close each stays one press. The colors,
   their ring and their places stay as drawn. */

@media (pointer: coarse) {
  .smbk-color-swatch-picker__item {
    position: relative;
  }

  .smbk-color-swatch-picker__item::after {
    content: '';
    position: absolute;
    inset: max(min(0%, (100% - var(--smbk-size-target-comfortable)) / 2), var(--smbk-space-inline-xs) / -2);
  }
}

/* ---- high contrast (forced colors) ---- */
/* Shadows are dropped: the chosen ring and the focus ring become outlines in the reader's colors. */
@media (forced-colors: active) {
  .smbk-color-swatch-picker__item[aria-selected="true"] {
    outline: var(--smbk-border-width-2) solid CanvasText;
    outline-offset: calc(-1 * var(--smbk-border-width-2));
  }

  .smbk-color-swatch-picker__item:focus-visible {
    outline: var(--smbk-border-width-2) solid Highlight;
    outline-offset: calc(-1 * var(--smbk-border-width-2));
  }
}
```

## Tokens it reads

```json
{
  "space": {
    "inline": {
      "xs": {
        "$type": "dimension",
        "$value": "{{space.4}}",
        "$description": "Gap between things side by side, extra small."
      }
    },
    "inset": {
      "xs": {
        "$type": "dimension",
        "$value": "{{space.4}}",
        "$description": "Padding inside a component, extra small."
      }
    }
  },
  "radius": {
    "container": {
      "sm": {
        "$type": "dimension",
        "$value": "{{radius.8}}",
        "$description": "Corners of cards, panels and dialogs, small."
      }
    },
    "control": {
      "md": {
        "$type": "dimension",
        "$value": "{{radius.6}}",
        "$description": "Corners of controls, medium."
      }
    },
    "full": {
      "$type": "dimension",
      "$value": "{{radius.9999}}",
      "$description": "Capsule: pills, chips, switches."
    }
  },
  "color": {
    "surface": {
      "hover": {
        "$type": "color",
        "$value": "{{color.alpha.grey-800.15}}",
        "$description": "A row or option under the pointer or the keyboard highlight: menu options, table rows. Translucent, so it works on any surface."
      }
    },
    "border": {
      "inverse": {
        "$type": "color",
        "$value": "{{color.grey.900}}",
        "$description": "Edge on the opposite surface."
      },
      "focus": {
        "$type": "color",
        "$value": "{{color.red.600}}",
        "$description": "Keyboard focus ring on controls."
      }
    }
  },
  "border-width": {
    "2": {
      "$type": "dimension",
      "$value": "2px",
      "$description": "Raw line thickness, 2 px. border-width/hairline, emphasis and accent point here."
    }
  },
  "opacity": {
    "disabled": {
      "$type": "number",
      "$value": 0.5,
      "$description": "Fade for disabled pictures and media (50%)."
    }
  },
  "size": {
    "target": {
      "comfortable": {
        "$type": "dimension",
        "$value": "{{size.44}}",
        "$description": "Comfortable touch target (44)."
      }
    }
  }
}
```

## Purpose

A set of colors to pick one from, such as a brand's colors, saved colors or colors to try, in rows that wrap. It is the fastest way to choose among a few set colors; for any color, use the color picker, which holds one at its foot.

## Anatomy

- The block, the list, in rows that wrap with the extra small step between items both ways.
- The item part, one per color: a color swatch inside the extra small inset, a 24 px swatch in a 32 px item, or a 16 px swatch in a 24 px item at the small size. The chosen item has a ring inside its edge with a gap round the swatch; the item with keyboard focus draws the ring in the focus color. Hover lays the hover surface behind the swatch, and a color that cannot be picked is dimmed.

## When to use

- To choose among a set of colors: a brand's palette, label colors, chart colors, saved colors.

## When not to use

- For any color at all. Use the [color picker](color-picker.md).
- To show colors that cannot be chosen. Use [color swatches](color-swatch.md).

## Behavior

A press on a color picks it. The picker holds its own choice from a first color, or follows the one the page gives it, and reports each color picked. A color matches the choice when its code and opacity are the same.

On a touch screen every color keeps its size and takes an invisible press area round it, reaching halfway into the gap between the colors, so each stays one press.

## Accessibility

### What it does for you

- It is a listbox, one stop in the Tab order: Tab reaches the chosen color, or the first.
- Each color is an option named in words, such as “vibrant red”, or by the name given; the chosen one is selected.
- The chosen color is shown by a ring and a gap, a shape, not by color alone.
- A color that cannot be picked is passed over by the arrow keys.
- In forced colors mode the rings become outlines in the reader's colors.
- On a touch screen every color keeps its size and takes an invisible press area round it, so each stays one press.

### What you must do

- Name the list for what the colors are for, such as “Brand color”.
- Give the colors their own names when they have them; otherwise each is read by a name made from its value.

### How to test

- Tab once: focus lands on the chosen color, or the first, and the next Tab leaves the list.
- With the arrow keys, Home and End, move through the colors, then press Space or Enter to pick one. A color that cannot be picked is skipped.
- With a screen reader, the list is read by its name, each color by its name, and the chosen one as selected.
- With text at 200% and the page 320 pixels wide, the colors wrap and each stays whole.
- In a forced-color mode, the chosen color and the one with focus each show an outline.

### Keyboard

| Key | What it does |
|---|---|
| Tab | Moves focus to the list, on the chosen color or the first. Tab again leaves it. |
| Left Arrow or Right Arrow | Moves to the previous or next color that can be picked. |
| Up Arrow or Down Arrow | Moves to the color above or below in the wrapped rows. |
| Home or End | Moves to the first or last color that can be picked. |
| Space or Enter | Picks the color with focus. |

## Usage rules

### Do

- Name the list for what the color is for.
- Give the colors their own names when they have them.

### Don't

- Offer colors so alike that the ring is the only way to tell which is which.
