Menu


Color slider


Picks one channel of a color, its hue, opacity, saturation or lightness, by dragging along a strip that shows the colors it moves through.

Customize the preview


Choices
Show
View
228°

Options


Color slider options
ChoiceValuesDefaultWhat it does
channelsmbk-color-slider--channel-<value>huealphasaturationlightnesshue
Which part of the color the slider changes. Alpha is the opacity, drawn over the checkerboard and labeled “Opacity”.
sizesmbk-color-slider--size-<value>mdsmmd
A 24 px strip with a 20 px thumb, or a 20 px strip with a 16 px thumb.

Partssmbk-color-slider__headersmbk-color-slider__labelsmbk-color-slider__valuesmbk-color-slider__tracksmbk-color-slider__gradientsmbk-color-slider__railsmbk-color-slider__thumb

Examples


Usage

The hue: the label and the value in degrees over a strip of every hue. Drag the thumb, press the strip, or use the arrow keys.

228°

Channels

Hue, saturation, lightness and opacity, each strip showing the colors its channel moves through; opacity over the checkerboard.

228°
75%
56%
100%

Sizes

A 24 px strip with a 20 px thumb, and a 20 px strip with a 16 px thumb.

228°
228°

Without the label row

With the top row hidden, as in the color picker’s panel, the label still names the slider for screen readers.

Disabled

The strip turns the disabled surface and the thumb shows no color.

228°
100%

Guidelines


Purpose

Changes one channel of a color, its hue, saturation, lightness or opacity, by dragging a thumb along a strip that shows the colors the channel moves through. Unlike the slider, which picks a number, the strip shows what each place on it looks like, and the thumb shows the color as it is now.

When to use

  • To change one part of a color, such as making a brand color lighter or a shadow more see-through.
  • Beside a color area, as the color picker's panel does: the hue slider sets the hue the area shows.

When not to use

Usage rules

Do

  • Pair the hue slider with the color area, sharing one color.
  • Keep the top row when the slider stands alone, so its value can be read.

Don't

  • Hide the top row of a slider standing alone: the reader cannot see the value.
  • Use it where an exact color matters without the color field beside it.

Anatomy

  • The header part, the top row: the label part at the start and the value part at the end, in the small body text with figures of one width. It can be left out; the label still names the slider for screen readers.
  • The track part, a strip with fully round ends and a hairline edge drawn inside it.
  • The gradient part, the colors the channel moves through, which the page paints as an inline background. The opacity strip has a color checker (smbk-color-checker) under it.
  • The rail part, the stretch the thumb's middle travels: the strip less half its height at each end, so the thumb never passes the round ends.
  • The thumb part, a color thumb (smbk-color-thumb), holding the hidden range input that takes the keys.

Behavior

Pressing anywhere on the strip moves the thumb there, and dragging moves it on. While dragged, the thumb grows a step and lifts; it changes size with the state motion; under reduced motion it changes size at once and only the shadow fades. The label row shows the value: the hue in degrees, the others as percentages.

The slider holds its own color from a first color, or follows the color the page gives it. It reports the new color as the thumb moves, and again when the reader lets go. Disabled, the strip turns the disabled surface, the thumb shows no color, and the value the disabled text color.

The strip's colors and the thumb's place depend on the color, so they are set by the wrapper. In plain markup, the page paints the gradient part, places the thumb with left as a percentage of the rail, and paints the thumb's color, updating them as the color changes; a disabled thumb takes data-disabled and no color.

On a touch screen an invisible area round the strip takes a press out to the comfortable touch target above and below it, and only halfway to a color area or another strip right beside it.

Accessibility


What it does for you

  • Each slider is a range input inside the thumb, one stop in the Tab order. Left and Right, or Up and Down, step the channel; Page Up and Page Down take larger steps; Home and End go to the ends.
  • A screen reader hears the label, the value and the color in words, such as “Hue, 225°, blue”.
  • The label names the slider even when the top row is hidden. The opacity slider is labeled “Opacity”.
  • The thumb shows a focus ring, with the page's color in the gap, while its input has keyboard focus.
  • The strip and the thumb keep their colors in forced colors mode, since the colors are what they show.

What you must do

  • Give the slider a label when the channel's own name, such as “Hue”, is not the name it should be read by. The channel's own name is used unless you give another.

How to test

  • Tab to the slider: one stop takes focus, and the thumb shows its ring in both themes and in a forced-color mode. Press the arrow keys, Page Up, Page Down, Home and End: the value moves and the color changes.
  • With a screen reader, the slider is read by its label, its value and the color in words, such as “Hue, 225°, blue”, also when the top row is hidden.
  • With the page 320 pixels wide, the strip fits and the thumb stays reachable.

Keyboard

Color slider keys
KeyWhat it does
Tab
Moves focus to the slider. It is one stop.
Left ArroworRight ArroworUp ArroworDown Arrow
Steps the channel.
Page UporPage Down
Takes a larger step.
HomeorEnd
Goes to the lowest or highest value.

Source


The files the color slider is made of. Its folder on GitHub (opens in a new tab) holds them with its wrapper and its document.

Stylesheet
color-slider.css
/* smbk-color-slider — Color slider. Figma "Color slider" 7407:320 (Channel × State × Size: md, sm).
 * A label row (the label in the strong label's look at the start, the value in Body XS at the end), the small
 * stack step above a strip with fully round ends. The strip's gradient is the colors the channel moves through,
 * which change with the color, so the wrapper paints it on the gradient part as an inline background; the
 * opacity strip has the checkerboard (smbk-color-checker) under it. A hairline edge is drawn inside the strip.
 * The thumb is the color thumb, placed along the rail: the strip less half its height at each end, so the thumb
 * never passes the strip's round ends. Disabled, the strip is the disabled surface, the thumb shows no color and
 * the value turns the disabled text color.
 * A different construction from the slider: React Aria's hidden range input inside the thumb takes the keys, and
 * the strip takes the pointer. */

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

/* ---- the label row ---- */

.smbk-color-slider__header {
  display: flex;
  align-items: center;
  justify-content: space-between;
  gap: var(--smbk-space-inline-md);
  min-width: 0;
}

.smbk-color-slider__value {
  margin-inline-start: auto;
  color: var(--smbk-color-text-default);
  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);
  font-variant-numeric: tabular-nums;
  white-space: nowrap;
}

.smbk-color-slider:has(input:disabled) .smbk-color-slider__value {
  color: var(--smbk-color-text-disabled);
}

/* ---- the strip ---- */

.smbk-color-slider__track {
  position: relative;
  box-sizing: border-box;
  width: 100%;
  height: var(--smbk-size-24);
  border-radius: var(--smbk-radius-full);
  background: var(--smbk-color-surface-disabled);
  touch-action: none;
  cursor: pointer;
}

.smbk-color-slider:has(input:disabled) .smbk-color-slider__track {
  cursor: not-allowed;
}

/* The colors, over the checkerboard on the opacity strip, with the edge drawn inside them. */
.smbk-color-slider__gradient {
  position: absolute;
  inset: 0;
  border-radius: inherit;
  box-shadow: inset 0 0 0 var(--smbk-border-width-hairline) var(--smbk-color-border-edge-shade-subtle);
  forced-color-adjust: none;
}

/* Where the thumb's middle travels: the strip less half its height at each end. */
.smbk-color-slider__rail {
  position: absolute;
  inset-block: 0;
  inset-inline: calc(var(--smbk-size-24) / 2);
}

/* ---- small ---- */

.smbk-color-slider--size-sm .smbk-color-slider__track {
  height: var(--smbk-size-20);
}

.smbk-color-slider--size-sm .smbk-color-slider__rail {
  inset-inline: calc(var(--smbk-size-20) / 2);
}

/* ---- touch: the strip takes an invisible press area ----
   On a touch screen an invisible area, centred on the strip, takes the press out to the comfortable target above and
   below it, so a finger can start a drag anywhere near it; where a color area or another strip stands right above or
   below, as in the color picker, it reaches only halfway into the gap between them. The strip and its thumb stay as
   drawn. */

@media (pointer: coarse) {
  .smbk-color-slider__track::after {
    content: '';
    position: absolute;
    inset-inline: 0;
    inset-block: min(0%, (100% - var(--smbk-size-target-comfortable)) / 2);
  }

  :is(.smbk-color-area, .smbk-color-slider) + .smbk-color-slider:not(:has(.smbk-color-slider__header)) .smbk-color-slider__track::after {
    inset-block-start: max(min(0%, (100% - var(--smbk-size-target-comfortable)) / 2), var(--smbk-space-stack-md) / -2);
  }

  .smbk-color-slider:has(+ :is(.smbk-color-area, .smbk-color-slider:not(:has(.smbk-color-slider__header)))) .smbk-color-slider__track::after {
    inset-block-end: max(min(0%, (100% - var(--smbk-size-target-comfortable)) / 2), var(--smbk-space-stack-md) / -2);
  }
}

/* ---- high contrast (forced colors) ---- */
/* The strip keeps its colors, which are what it shows; its edge takes the reader's text color. */
@media (forced-colors: active) {
  .smbk-color-slider__track {
    outline: var(--smbk-border-width-hairline) solid CanvasText;
  }
}
Tokens it reads
Color slider tokens
Token and CSSValuePreviewFoundation
space.stack.sm--smbk-space-stack-smcomfortable: 8pxcompact: 6pxchanges with densitySpacing
space.inline.md--smbk-space-inline-mdcomfortable: 8pxcompact: 6pxchanges with densitySpacing
color.text.default--smbk-color-text-defaultlight: #232527dark: #e7ebf0changes with themeColor
typography.body-xs--smbk-typography-body-xs-font-family--smbk-typography-body-xs-font-size--smbk-typography-body-xs-font-weight--smbk-typography-body-xs-line-height--smbk-typography-body-xs-letter-spacing--smbk-typography-body-xs-text-transformfontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 12pxfontWeight: 400lineHeight: 1.5letterSpacing: 0px

The quick brown fox

Typography
color.text.disabled--smbk-color-text-disabledlight: #7c8692dark: #606a75changes with themeColor
size.24--smbk-size-2424pxSize
radius.full--smbk-radius-full9999pxRadius
color.surface.disabled--smbk-color-surface-disabledlight: #e7ebf0dark: #373d43changes with themeColor
border-width.hairline--smbk-border-width-hairline1pxBorder width
color.border.edge-shade-subtle--smbk-color-border-edge-shade-subtlelight: #0000001adark: #00000033changes with themeColor
size.20--smbk-size-2020pxSize
size.target.comfortable--smbk-size-target-comfortable44pxSize
space.stack.md--smbk-space-stack-mdcomfortable: 12pxcompact: 8pxchanges with densitySpacing
Manifest
color-slider.manifest.json
{
  "name": "color-slider",
  "block": "smbk-color-slider",
  "summary": "Picks one channel of a color, its hue, opacity, saturation or lightness, by dragging along a strip that shows the colors it moves through.",
  "adapt": "css",
  "axes": {
    "channel": {
      "values": [
        "hue",
        "alpha",
        "saturation",
        "lightness"
      ],
      "default": "hue",
      "description": "Which part of the color the slider changes. Alpha is the opacity, drawn over the checkerboard and labeled “Opacity”."
    },
    "size": {
      "values": [
        "md",
        "sm"
      ],
      "default": "md",
      "description": "A 24 px strip with a 20 px thumb, or a 20 px strip with a 16 px thumb."
    }
  },
  "flags": {},
  "parts": [
    "header",
    "label",
    "value",
    "track",
    "gradient",
    "rail",
    "thumb"
  ],
  "figmaNodeId": "7407:320"
}