# Color range

The steps of one color range in a strip, each with its swatch, its name and its contrast against white, with the step in use ringed.

Block: `smbk-color-range`. 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 |
|---|---|---|---|

Parts: `smbk-color-range__head`, `smbk-color-range__title`, `smbk-color-range__meta`, `smbk-color-range__steps`, `smbk-color-range__step`, `smbk-color-range__swatch`, `smbk-color-range__name`, `smbk-color-range__ratio`, `smbk-color-range__hidden`

## Markup

```html
<div class="smbk-color-range">
  <div class="smbk-color-range__head">
    <span id="color-range-1" class="smbk-color-range__title">Brand</span>
    <span class="smbk-color-range__meta">11 steps · 600 in use</span>
  </div>
  <ol class="smbk-color-range__steps" aria-labelledby="color-range-1">
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">very light pale red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(254, 249, 248, 1)"></span></span>
      <span class="smbk-color-range__name">50</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">1.0:1</span><span class="smbk-color-range__hidden">, contrast 1.0 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">very light pale red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(254, 242, 241, 1)"></span></span>
      <span class="smbk-color-range__name">100</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">1.0:1</span><span class="smbk-color-range__hidden">, contrast 1.0 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">very light pale red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(254, 229, 225, 1)"></span></span>
      <span class="smbk-color-range__name">200</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">1.1:1</span><span class="smbk-color-range__hidden">, contrast 1.1 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">very light pale red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(254, 189, 178, 1)"></span></span>
      <span class="smbk-color-range__name">300</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">1.5:1</span><span class="smbk-color-range__hidden">, contrast 1.5 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">light vibrant red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(254, 125, 109, 1)"></span></span>
      <span class="smbk-color-range__name">400</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">2.5:1</span><span class="smbk-color-range__hidden">, contrast 2.5 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">vibrant red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(243, 67, 54, 1)"></span></span>
      <span class="smbk-color-range__name">500</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">3.7:1</span><span class="smbk-color-range__hidden">, contrast 3.7 to 1</span></span>
    </li>
    <li class="smbk-color-range__step" aria-current="true">
      <span class="smbk-color-range__hidden">dark vibrant red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(204, 13, 13, 1)"></span></span>
      <span class="smbk-color-range__name">600</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">5.7:1</span><span class="smbk-color-range__hidden">, contrast 5.7 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">dark vibrant red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(165, 29, 23, 1)"></span></span>
      <span class="smbk-color-range__name">700</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">7.5:1</span><span class="smbk-color-range__hidden">, contrast 7.5 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">dark red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(118, 24, 18, 1)"></span></span>
      <span class="smbk-color-range__name">800</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">10.9:1</span><span class="smbk-color-range__hidden">, contrast 10.9 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">very dark grayish red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(75, 19, 14, 1)"></span></span>
      <span class="smbk-color-range__name">900</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">15.0:1</span><span class="smbk-color-range__hidden">, contrast 15.0 to 1</span></span>
    </li>
    <li class="smbk-color-range__step">
      <span class="smbk-color-range__hidden">very dark grayish red, </span>
      <span
        aria-hidden="true"
        class="smbk-color-swatch smbk-color-swatch--size-lg smbk-color-swatch--shape-square smbk-color-range__swatch"
      ><span class="smbk-color-checker"></span><span class="smbk-color-swatch__color" style="background-color:rgba(42, 4, 3, 1)"></span></span>
      <span class="smbk-color-range__name">950</span>
      <span class="smbk-color-range__ratio"><span aria-hidden="true">18.7:1</span><span class="smbk-color-range__hidden">, contrast 18.7 to 1</span></span>
    </li>
  </ol>
</div>
```

## React

```tsx
import { ColorRange } from './design-system/components/color-range/color-range.js';

<ColorRange name="Brand" steps={[{ name: "50", color: "#fef9f8" }, { name: "100", color: "#fef2f1" }, { name: "200", color: "#fee5e1" }, { name: "300", color: "#febdb2" }, { name: "400", color: "#fe7d6d" }, { name: "500", color: "#f34336" }, { name: "600", color: "#cc0d0d" }, { name: "700", color: "#a51d17" }, { name: "800", color: "#761812" }, { name: "900", color: "#4b130e" }, { name: "950", color: "#2a0403" }]} defaultValue="600" />
```

## Stylesheet

```css
/* smbk-color-range — Color range. Figma "Color range" 7416:21, a strip of "ColorRangeStep" 7416:19 (State: Default, Hover,
 * Selected, Focus).
 * A name row (the range's name in Label MD and a line of facts in Body XS) over the steps, which share the width in equal
 * columns, the extra small inline step apart. Each step is a color swatch (smbk-color-swatch) stretched to the width of its
 * column and 40 tall, its name in Label SM and its contrast ratio in Body XS under it. The words sit on the page, never on
 * the color, so no step needs a text color of its own. The step in use rings its swatch inside its edge in the inverse
 * border color, two pixels wide: a shape as well as a color. In a range a reader can pick from, hover draws the swatch's
 * edge in the strong border color and keyboard focus draws the ring in the focus color. In a narrow space the eleven
 * steps wrap onto two rows, so the names and ratios keep their room. */

.smbk-color-range {
  display: flex;
  flex-direction: column;
  gap: var(--smbk-space-stack-sm);
  min-width: 0;
}

/* The block frames the words it hides for screen readers, so they stay inside it wherever it is placed: without a
   frame they hang from the page itself and stretch it, past the end of an area that scrolls. No weight, so a parent
   that places the block keeps its say. */
:where(.smbk-color-range) {
  position: relative;
}

.smbk-color-range__head {
  display: flex;
  flex-wrap: wrap;
  align-items: baseline;
  gap: var(--smbk-space-inline-md);
}

.smbk-color-range__title {
  color: var(--smbk-color-text-default);
  font-family: var(--smbk-typography-label-md-font-family);
  font-size: var(--smbk-typography-label-md-font-size);
  font-weight: var(--smbk-typography-label-md-font-weight);
  line-height: var(--smbk-typography-label-md-line-height);
  letter-spacing: var(--smbk-typography-label-md-letter-spacing);
}

.smbk-color-range__meta,
.smbk-color-range__ratio {
  color: var(--smbk-color-text-subtle);
  font-family: var(--smbk-typography-body-xs-font-family);
  font-size: var(--smbk-typography-body-xs-font-size);
  font-weight: var(--smbk-typography-body-xs-font-weight);
  line-height: var(--smbk-typography-body-xs-line-height);
  letter-spacing: var(--smbk-typography-body-xs-letter-spacing);
}

/* The steps share the width equally, however many there are. */
.smbk-color-range__steps {
  display: grid;
  grid-auto-columns: minmax(0, 1fr);
  grid-auto-flow: column;
  gap: var(--smbk-space-stack-sm) var(--smbk-space-inline-xs);
  margin: 0;
  padding: 0;
  list-style: none;
  outline: none;
}

.smbk-color-range__step {
  display: flex;
  flex-direction: column;
  gap: var(--smbk-space-stack-xs);
  min-width: 0;
  outline: none;
  -webkit-tap-highlight-color: transparent;
}

.smbk-color-range__step[role="option"] {
  cursor: pointer;
}

.smbk-color-range__name {
  color: var(--smbk-color-text-default);
  font-family: var(--smbk-typography-label-sm-font-family);
  font-size: var(--smbk-typography-label-sm-font-size);
  font-weight: var(--smbk-typography-label-sm-font-weight);
  line-height: var(--smbk-typography-label-sm-line-height);
  letter-spacing: var(--smbk-typography-label-sm-letter-spacing);
}

.smbk-color-range__name,
.smbk-color-range__ratio {
  overflow-wrap: anywhere;
  font-variant-numeric: tabular-nums;
}

/* The swatch stretched to its column, 40 tall, with the control's small corner. Two classes, so these win over the
   swatch's own size whichever stylesheet loads first. */
.smbk-color-range__swatch.smbk-color-swatch {
  width: 100%;
  height: var(--smbk-size-40);
  border-radius: var(--smbk-radius-control-sm);
}

@media (hover: hover) {
  .smbk-color-range__step[role="option"]:hover .smbk-color-range__swatch.smbk-color-swatch::after {
    border-color: var(--smbk-color-border-strong);
  }
}

/* The step in use: aria-current in a list, aria-selected in a range a reader picks from. */
.smbk-color-range__step[aria-current="true"] .smbk-color-range__swatch.smbk-color-swatch::after,
.smbk-color-range__step[aria-selected="true"] .smbk-color-range__swatch.smbk-color-swatch::after {
  border-width: var(--smbk-border-width-2);
  border-color: var(--smbk-color-border-inverse);
}

.smbk-color-range__step:focus-visible .smbk-color-range__swatch.smbk-color-swatch::after {
  border-width: var(--smbk-border-width-2);
  border-color: var(--smbk-color-border-focus);
}

/* Words for screen readers only: the ratio said in full. */
/* .smbk-color-range__hidden: hidden from view, kept for screen readers and the keyboard, by the shared rule in visually-hidden/visually-hidden.css. */

/* ---- the narrow form: the steps wrap onto rows of six, so their names and ratios keep their room ---- */
@container style(--smbk-layout: narrow) {
  .smbk-color-range__steps {
    grid-auto-flow: row;
    grid-template-columns: repeat(6, minmax(0, 1fr));
  }
}

/* ---- high contrast (forced colors) ---- */
/* The rings are the swatch's edge, which keeps the reader's colors: the step in use and the focused step draw it in
   the highlight color, so neither is lost. */
@media (forced-colors: active) {
  .smbk-color-range__step[aria-current="true"] .smbk-color-range__swatch.smbk-color-swatch::after,
  .smbk-color-range__step[aria-selected="true"] .smbk-color-range__swatch.smbk-color-swatch::after {
    border-color: CanvasText;
  }

  .smbk-color-range__step:focus-visible .smbk-color-range__swatch.smbk-color-swatch::after {
    border-color: Highlight;
  }
}
```

## Tokens it reads

```json
{
  "space": {
    "stack": {
      "sm": {
        "$type": "dimension",
        "$value": "{{space.8}}",
        "$description": "Gap between things stacked one above another, small."
      },
      "xs": {
        "$type": "dimension",
        "$value": "{{space.4}}",
        "$description": "Gap between things stacked one above another, extra small."
      }
    },
    "inline": {
      "md": {
        "$type": "dimension",
        "$value": "{{space.8}}",
        "$description": "Gap between things side by side, medium."
      },
      "xs": {
        "$type": "dimension",
        "$value": "{{space.4}}",
        "$description": "Gap between things side by side, extra small."
      }
    }
  },
  "color": {
    "text": {
      "default": {
        "$type": "color",
        "$value": "{{color.grey.900}}",
        "$description": "Main text."
      },
      "subtle": {
        "$type": "color",
        "$value": "{{color.grey.700}}",
        "$description": "Secondary text: descriptions, metadata."
      }
    },
    "border": {
      "strong": {
        "$type": "color",
        "$value": "{{color.grey.400}}",
        "$description": "Stronger edges and separators."
      },
      "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."
      }
    }
  },
  "typography": {
    "label-md": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "14px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label MD: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    },
    "body-xs": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "12px",
        "fontWeight": 400,
        "lineHeight": 1.5,
        "letterSpacing": "0px"
      }
    },
    "label-sm": {
      "$type": "typography",
      "$value": {
        "fontFamily": "Geist, Geist Fallback, system-ui, sans-serif",
        "fontSize": "12px",
        "fontWeight": 500,
        "lineHeight": 1.4,
        "letterSpacing": "0px"
      },
      "$description": "Label SM: labels on controls and short UI text (buttons, chips, tabs, menu headings). Geist Medium, sentence case. Code and keys use Code SM and Code MD."
    }
  },
  "size": {
    "40": {
      "$type": "dimension",
      "$value": "40px",
      "$description": "Raw size step, 40 px. Only for fixed sizes inside a component; semantic sizes (size/control, icon, mark) point here."
    }
  },
  "radius": {
    "control": {
      "sm": {
        "$type": "dimension",
        "$value": "{{radius.4}}",
        "$description": "Corners of controls, small."
      }
    }
  },
  "border-width": {
    "2": {
      "$type": "dimension",
      "$value": "2px",
      "$description": "Raw line thickness, 2 px. border-width/hairline, emphasis and accent point here."
    }
  }
}
```

## Purpose

Shows every step of one color range in a strip, lightest to darkest, each with its swatch, its name and its contrast against white, so a step's number means the same thing in every range. It is for tools that build or explain a color system, such as a token editor or a theme builder. To show a few unrelated colors, use color swatches; to choose any color, use the color picker.

## Anatomy

- The block: a column with the name row over the steps.
- The head part, the name row: the range's name (the title part, in Label MD) and a line of facts (the meta part, in Body XS), such as how many steps there are and which is in use. It can be left out; the name still names the strip.
- The steps part: the steps side by side, sharing the width equally. In a narrow space they wrap onto rows of six.
- The step part, one per step: a color swatch stretched to the step's width and 40 px tall (the swatch part), the step's name in Label SM (the name part) and its ratio in Body XS (the ratio part), which can be left out. The words sit on the page under the color, never on it.
- The step in use rings its swatch inside its edge. In a range the reader can pick from, hover draws the swatch's edge stronger, and keyboard focus draws the ring in the focus color.

## When to use

- To show a color range as a whole: a brand range, a neutral range, a data range.
- To let a reader choose which step of a range a role uses.

## When not to use

- For a handful of colors that are not one range. Use [color swatches](color-swatch.md), or the [color swatch picker](color-swatch-picker.md) to choose one.
- To check one text color against one background. Use the [contrast pair](contrast-pair.md).

## Behavior

The ratio under each step is worked out from its color against white, or against the color given, and written with one decimal, never rounded up past what it is. The range holds the step in use from a first value, or follows the one the page gives it.

Given a change handler, the strip becomes a list to pick from: a press on a step picks it, and the page hears the step's name. Without one, the strip only shows the range, with the step in use ringed.

## Accessibility

### What it does for you

- The strip is a list named by the range's name. Each step is told in words: its color, such as "vibrant red", its name and its contrast ("contrast 4.8 to 1"). The step in use is marked as the current one.
- A range to pick from is a listbox, one stop in the Tab order: Tab reaches the step in use, the arrow keys move between steps, Home and End go to the first and last, and Space or Enter picks the step with focus.
- The step in use is shown by a ring, a shape, as well as by the line of facts, never by color alone.
- In forced colors mode the rings take the reader's own colors.

### What you must do

- Give the words the range says by itself, such as the ratio read aloud, in the page's own language. They keep their English unless the page gives its own.

### How to test

- Tab to a range you can pick from: one stop takes focus, on the step in use, with the ring showing in both themes and in a forced-color mode. Move with the arrow keys, then press Space or Enter to pick.
- With a screen reader, the range is read by its name, each step by its color, name and contrast, and the step in use as current.
- Read the range with the colors taken away: the ring and the line of facts still show the step in use.
- With text at 200% and the page 320 pixels wide, the steps and their facts stay readable.

### Keyboard

| Key | What it does |
|---|---|
| Tab | Moves focus to the step in use. The range is one stop. |
| Right Arrow or Down Arrow | Moves focus to the next step. In a right-to-left language, Right Arrow moves to the previous step. |
| Left Arrow or Up Arrow | Moves focus to the previous step. In a right-to-left language, Left Arrow moves to the next step. |
| Home or End | Moves focus to the first or last step. |
| Space or Enter | Picks the step with focus. |

## Usage rules

### Do

- Show every step of the range, in order.
- Name each step the way the system names it, such as "600".

### Don't

- Show only some steps, which hides how the range moves from light to dark.
- Put words on the colors: the ratio is under the step, where its color cannot hide it.
