Menu


Chip


A small selectable token — a filter, a choice, a person — that can carry an avatar and be removed.

Customize the preview


Choices
Show
Flags
View
Ada Okafor

Options


Chip options
ChoiceValuesDefaultWhat it does
tonesmbk-chip--tone-<value>defaultbrandoutlineinversebrand
Which action family the chip draws from; default is a see-through gray that shows on every surface.
sizesmbk-chip--size-<value>mdsmmd
The pill scale shared with the badge and the tag: 32 and 24 tall.
selectedsmbk-chip--selectedOn or offOff
The chip is currently chosen: pressed in, with a tick before its label. Given as true or false, the chip is a toggle and announces pressed or not pressed; left out, it is a plain button.

Partssmbk-chip__ticksmbk-chip__avatarsmbk-chip__labelsmbk-chip__remove

Examples


Usage

A chip on its own: the brand tone at the default size.

Tones

Four tones, drawn from the action color families.

Selected

A chosen chip is pressed in and shows a tick, so the choice shows by more than its color.

Toggles

A row of filters: every chip is a toggle, so the ones not chosen say "not pressed" as well.

Pressed by a script

A page built ahead of time can press a chip with its own script, setting aria-pressed alone: the chip shows its tick as when React turns it on.

Removable

The remove control appears when a handler is given; its cross sits in a box large enough to press.

Status: activeOwner: me

Guidelines


Purpose

A small capsule that stands for one choice in a set — a filter, a category, a person — and can be pressed to select it or removed from the set. It is interactive, which is what separates it from a badge, and it is one of many, which is what separates it from a button.

When to use

  • Filters a person switches on and off.

  • People or items chosen into a field, each removable.

  • A row of categories where one or several may be selected.

  • A short row of related places, such as a site's services, drawn as chips: each chip is then a link.

When not to use

  • For a single action. Use a button.
  • For an inert status word. Use a badge or a tag.

Usage rules

Do

  • Keep labels short; a chip that wraps is a card.
  • Use the small size only where the row is dense and the chips are many.
  • Give every chip in a filter row its selected state, on or off, so each one says it is a toggle.

Don't

  • Color chips by category with the tones. Tones are emphasis, not meaning.
  • Put an icon-only chip on a page. A chip is text.
Do

Keep filter chips in one tone and let the chosen ones show it, so color means chosen.

Don't

A different tone per category suggests a meaning that is not there and hides which chips are chosen.

Do

Keep the label to a word or two, so the chip stays on one line.

Don't

A sentence in a chip stretches it until it reads like a card.

Anatomy

  • The block, a capsule of fixed height by size, on the same scale as the badge and the tag. The default tone is a see-through gray with no edge, so it shows on any surface; the others draw a hairline edge.
  • The tick part, a check mark before the label of a selected toggle chip, in the avatar's place.
  • The avatar part, an optional small avatar before the label, dimmed when the chip is disabled.
  • The label part, the text, carrying its own horizontal inset.
  • The remove part, an optional small control with a circled cross that removes the chip, inside a box large enough to press.

A toggle chip that is on is drawn from its pressed attribute, as the toggle button is; the selected modifier draws the same, for markup that sets it.

Behavior

A selectable chip toggles between unselected and selected when pressed. Hovered, the brand and inverse tones lift with the first elevation level and the default tone darkens; pressed and selected, every tone sinks in and the selected chip shows a tick before its label, so the choice shows by more than color. A removable chip does not toggle; its remove control calls back and the page takes it out of the set.

A chip given an address is a link: pressing it goes there. It is never selected and never removable.

Whether a chip is a toggle is decided by the selected prop being given at all. A filter or choice chip is always given it, true when chosen and false when not. A chip that only acts, such as a suggestion, leaves it out.

A toggle chip carries its tick whether it is on or off, and shows it while it is pressed, so a page built ahead of time can press a chip with a script of its own, setting aria-pressed alone, and get the same tick as when React turns it on.

In markup, a link chip is an a element carrying the same classes, so it looks the same and has the same hover and focus. The React wrapper's types refuse selected and onRemove on a chip given an address.

On a touch screen a chip that is pressed, and a remove cross, keep their size and take an invisible press area round them, out to the comfortable touch target; a removable chip takes the press on its cross alone. Where chips stand closer, as in a filter bar or a combobox, each area stops halfway to the next.

Accessibility


What it does for you

  • A selectable chip is a real button with a pressed state exposed to assistive technology. Given selected as true or false, the wrapper marks it pressed or not pressed, so a screen reader says it is a toggle and whether it is on even while it is off.
  • The wrapper derives the pressed state from selected; a page rendered by React does not set it itself. A page's own script that presses a chip sets aria-pressed, and the tick follows it.
  • A removable chip is plain text plus a real remove button, which the wrapper requires an accessible name for. The button is at least 24 by 24 pixels, the least a press needs, however small its cross.
  • A chip given an address is a real link and is announced as one.
  • The focus ring is the system rule on the chip. On the remove control it is drawn round the cross itself; on a brand or inverse chip it takes the chip's own text color, so it shows on the fill.

What you must do

  • Leave selected out for a chip that only acts: it then says neither pressed nor not pressed. Give it for a filter, which must say whether it is on.
  • Give a removable chip's remove button an accessible name that says what is removed.
  • Never make a chip both toggle and remove: that would need a button inside a button.
  • Put a row of chips that are links in a navigation landmark or a named group, so the row says what its places are.

How to test

  • Tab to a chip: the focus ring shows in both themes and in a forced-color mode, round the cross on a remove button. Press Enter, then Space: each toggles or acts once.
  • With a screen reader, a selectable chip is read as a toggle button, on or off, a link chip as a link, and a remove button by what it removes.
  • On a touch screen, the remove cross is easy to hit.
  • With text at 200% and the page 320 pixels wide, the label stays whole.

Keyboard

Chip keys
KeyWhat it does
Tab
Moves focus to the chip, then to its remove button when it has one.
Enter
Presses the chip or its remove button, or follows the chip when it is a link.
Space
Presses the chip or its remove button. A chip that is a link is not followed by Space.

Source


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

Stylesheet
chip.css
/* smbk-chip — Chip. Figma "Chip" 4253:1311.
 * A capsule with an optional avatar or tick, a label and an optional remove control, a gap between them.
 * The label's own frame carries a further inset on both sides, as Figma's label frame does. Figma draws
 * the edge inside the chip, so the padding gives the edge's width back; the default tone has no edge of
 * its own, and draws a clear one so it keeps the same size.
 * On is the toggle chip's aria-pressed, as the toggle button's is, so the look and what a screen reader hears
 * agree; the selected class draws the same, for markup that sets it. */

.smbk-chip {
  box-sizing: border-box;
  display: inline-flex;
  align-items: center;
  gap: var(--smbk-space-inline-sm);
  height: var(--smbk-size-32);
  padding: 0 calc(var(--smbk-space-inset-xs) - var(--smbk-border-width-hairline));
  border: var(--smbk-border-width-hairline) solid var(--smbk-color-action-brand-border);
  border-radius: var(--smbk-radius-full);
  background: var(--smbk-color-action-brand-background);
  color: var(--smbk-color-action-brand-foreground);
  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);
  white-space: nowrap;
  text-decoration: none;
  cursor: pointer;
  -webkit-user-select: none;
  user-select: none;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.smbk-chip:focus-visible {
  outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
  outline-offset: var(--smbk-focus-ring-offset);
}

.smbk-chip:disabled,
.smbk-chip[aria-disabled="true"] {
  cursor: not-allowed;
  pointer-events: none;
}

.smbk-chip__label {
  display: block;
  padding: 0 var(--smbk-space-inset-sm);
}

.smbk-chip__avatar {
  flex-shrink: 0;
}

.smbk-chip:disabled .smbk-chip__avatar,
.smbk-chip[aria-disabled="true"] .smbk-chip__avatar {
  opacity: var(--smbk-opacity-disabled);
}

/* A selected chip shows a tick where the avatar would be, so the choice shows by more than its fill, and
   a little more room before it. */
.smbk-chip__tick {
  font-size: var(--smbk-size-icon-sm);
}

/* A toggle carries its tick off as well as on, so a page's script that sets aria-pressed shows it; it shows only while
   the chip is on (aria-pressed, or the selected class), and then hides the avatar. */
.smbk-chip:not([aria-pressed="true"], .smbk-chip--selected) > .smbk-chip__tick,
.smbk-chip:is([aria-pressed="true"], .smbk-chip--selected) > .smbk-chip__tick ~ .smbk-chip__avatar {
  display: none;
}

.smbk-chip:is([aria-pressed="true"], .smbk-chip--selected):has(> .smbk-chip__tick) {
  padding-inline-start: calc(var(--smbk-space-inset-md) - var(--smbk-border-width-hairline));
}

/* The cross is the chip's icon size, inside a 24 px box, the least a press needs; the box reaches past the
   cross into the gap and the padding, so the cross sits where Figma draws it. The focus ring is drawn on
   the cross's own edge. */
.smbk-chip__remove {
  box-sizing: border-box;
  display: inline-flex;
  flex-shrink: 0;
  align-items: center;
  justify-content: center;
  width: var(--smbk-size-target-min);
  height: var(--smbk-size-target-min);
  margin: calc((var(--smbk-size-icon-sm) - var(--smbk-size-target-min)) / 2);
  padding: 0;
  border: 0;
  background: none;
  color: inherit;
  cursor: pointer;
  appearance: none;
  -webkit-tap-highlight-color: transparent;
  touch-action: manipulation;
}

.smbk-chip__remove > .smbk-icon {
  font-size: var(--smbk-size-icon-sm);
  border-radius: var(--smbk-radius-full);
}

.smbk-chip__remove:focus-visible {
  outline: none;
}

.smbk-chip__remove:focus-visible > .smbk-icon {
  outline: var(--smbk-focus-ring-width) solid var(--smbk-color-border-focus);
  outline-offset: 0;
}

/* On the brand and inverse fills the focus color would not show, so the ring takes the chip's own text color. */
.smbk-chip--tone-brand .smbk-chip__remove:focus-visible > .smbk-icon,
.smbk-chip--tone-inverse .smbk-chip__remove:focus-visible > .smbk-icon {
  outline-color: currentColor;
}

/* ---- size sm ---- */

.smbk-chip--size-sm {
  height: var(--smbk-size-24);
  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-chip--size-sm .smbk-chip__label {
  padding: 0 var(--smbk-space-inset-xs);
}

.smbk-chip--size-sm .smbk-chip__tick,
.smbk-chip--size-sm .smbk-chip__remove > .smbk-icon {
  font-size: var(--smbk-size-icon-xs);
}

.smbk-chip--size-sm:is([aria-pressed="true"], .smbk-chip--selected):has(> .smbk-chip__tick) {
  padding-inline-start: calc(var(--smbk-space-inset-sm) - var(--smbk-border-width-hairline));
}

.smbk-chip--size-sm .smbk-chip__remove {
  margin: calc((var(--smbk-size-icon-xs) - var(--smbk-size-target-min)) / 2);
}

/* ---- tone: brand (default) ---- */

@media (hover: hover) {
  .smbk-chip--tone-brand:hover {
    background: var(--smbk-color-action-brand-background-hover);
    border-color: var(--smbk-color-action-brand-border-hover);
    box-shadow: var(--smbk-elevation-raised);
  }
}

.smbk-chip--tone-brand:active,
.smbk-chip--tone-brand[aria-pressed="true"],
.smbk-chip--tone-brand.smbk-chip--selected {
  background: var(--smbk-color-action-brand-background-pressed);
  border-color: var(--smbk-color-action-brand-border-hover);
  box-shadow: var(--smbk-elevation-inset-strong);
}

.smbk-chip--tone-brand:disabled,
.smbk-chip--tone-brand[aria-disabled="true"] {
  background: var(--smbk-color-action-brand-background-disabled);
  border-color: var(--smbk-color-action-brand-border-disabled);
  color: var(--smbk-color-action-brand-foreground-disabled);
  box-shadow: none;
}

/* ---- tone: default, the see-through gray with no edge ---- */

.smbk-chip--tone-default {
  background: var(--smbk-color-surface-neutral-subtle);
  border-color: transparent;
  color: var(--smbk-color-action-default-foreground);
}

@media (hover: hover) {
  .smbk-chip--tone-default:hover {
    background: var(--smbk-color-surface-hover);
  }
}

.smbk-chip--tone-default:active,
.smbk-chip--tone-default[aria-pressed="true"],
.smbk-chip--tone-default.smbk-chip--selected {
  background: var(--smbk-color-action-default-background-pressed);
  box-shadow: var(--smbk-elevation-inset-strong);
}

.smbk-chip--tone-default:disabled,
.smbk-chip--tone-default[aria-disabled="true"] {
  background: var(--smbk-color-action-disabled-background);
  color: var(--smbk-color-action-disabled-foreground);
  box-shadow: none;
}

/* ---- tone: outline ---- */

.smbk-chip--tone-outline {
  background: transparent;
  border-color: var(--smbk-color-action-outline-border);
  color: var(--smbk-color-action-outline-foreground);
}

@media (hover: hover) {
  .smbk-chip--tone-outline:hover {
    background: var(--smbk-color-action-outline-background-hover);
    border-color: var(--smbk-color-action-outline-border-hover);
  }
}

.smbk-chip--tone-outline:active,
.smbk-chip--tone-outline[aria-pressed="true"],
.smbk-chip--tone-outline.smbk-chip--selected {
  background: var(--smbk-color-action-outline-background-pressed);
  border-color: var(--smbk-color-action-outline-border-hover);
  box-shadow: var(--smbk-elevation-inset-strong);
}

.smbk-chip--tone-outline:disabled,
.smbk-chip--tone-outline[aria-disabled="true"] {
  background: transparent;
  border-color: var(--smbk-color-action-disabled-border);
  color: var(--smbk-color-action-outline-foreground-disabled);
  box-shadow: none;
}

/* ---- tone: inverse ---- */

.smbk-chip--tone-inverse {
  background: var(--smbk-color-action-inverse-background);
  border-color: var(--smbk-color-action-inverse-border);
  color: var(--smbk-color-action-inverse-foreground);
}

@media (hover: hover) {
  .smbk-chip--tone-inverse:hover {
    background: var(--smbk-color-action-inverse-background-hover);
    border-color: var(--smbk-color-action-inverse-border-hover);
    box-shadow: var(--smbk-elevation-raised);
  }
}

.smbk-chip--tone-inverse:active,
.smbk-chip--tone-inverse[aria-pressed="true"],
.smbk-chip--tone-inverse.smbk-chip--selected {
  background: var(--smbk-color-action-inverse-background-pressed);
  border-color: var(--smbk-color-action-inverse-border-hover);
  box-shadow: var(--smbk-elevation-inset);
}

.smbk-chip--tone-inverse:disabled,
.smbk-chip--tone-inverse[aria-disabled="true"] {
  background: var(--smbk-color-action-disabled-background);
  border-color: var(--smbk-color-action-disabled-border);
  color: var(--smbk-color-action-disabled-foreground);
  box-shadow: none;
}

/* ---- touch: a chip and its remove cross take invisible press areas ----
   On a touch screen an invisible area, centred on a chip that is pressed and on a remove cross, takes the press out to
   the comfortable target in each direction it falls short of it; a chip that only carries a remove cross takes the
   press on the cross alone. The chip, its focus ring and its place stay as drawn. A component that sets chips closer
   together stops their areas halfway to the next one. */

@media (pointer: coarse) {
  :where(button, a[href]).smbk-chip {
    position: relative;
  }

  :where(button, a[href]).smbk-chip::after {
    content: '';
    position: absolute;
    inset: min(0%, (100% - var(--smbk-size-target-comfortable)) / 2);
  }

  .smbk-chip__remove {
    position: relative;
  }

  .smbk-chip__remove::after {
    content: '';
    position: absolute;
    inset: min(0%, (100% - var(--smbk-size-target-comfortable)) / 2);
  }
}

/* ---- high contrast (forced colors) ---- */
/* In Windows high-contrast mode the browser drops fills and shadows; this puts the meaning back with the
   user's own colors. Nothing here applies outside that mode. */

@media (forced-colors: active) {
  /* A toggle chip that is on (aria-pressed, or the selected class) is filled with Highlight. */
  .smbk-chip[aria-pressed="true"],
  .smbk-chip.smbk-chip--selected {
    forced-color-adjust: none;
    border-color: Highlight;
    background: Highlight;
    color: HighlightText;
    box-shadow: none;
  }

  .smbk-chip[aria-pressed="true"]:focus-visible,
  .smbk-chip.smbk-chip--selected:focus-visible {
    outline-color: CanvasText;
  }
}
Tokens it reads
Chip tokens
Token and CSSValuePreviewFoundation
space.inline.sm--smbk-space-inline-smcomfortable: 6pxcompact: 4pxchanges with densitySpacing
size.32--smbk-size-3232pxSize
space.inset.xs--smbk-space-inset-xs4pxSpacing
border-width.hairline--smbk-border-width-hairline1pxBorder width
color.action.brand.border--smbk-color-action-brand-border#ffffff1aColor
radius.full--smbk-radius-full9999pxRadius
color.action.brand.background--smbk-color-action-brand-background#cc0d0dColor
color.action.brand.foreground--smbk-color-action-brand-foreground#f9fafbColor
typography.label-md--smbk-typography-label-md-font-family--smbk-typography-label-md-font-size--smbk-typography-label-md-font-weight--smbk-typography-label-md-line-height--smbk-typography-label-md-letter-spacing--smbk-typography-label-md-text-transformfontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 14pxfontWeight: 500lineHeight: 1.4letterSpacing: 0px

The quick brown fox

Typography
focus.ring.width--smbk-focus-ring-width2pxFocus
color.border.focus--smbk-color-border-focuslight: #cc0d0ddark: #f34336changes with themeColor
focus.ring.offset--smbk-focus-ring-offset2pxFocus
space.inset.sm--smbk-space-inset-smcomfortable: 6pxcompact: 4pxchanges with densitySpacing
opacity.disabled--smbk-opacity-disabled0.5Opacity
size.icon.sm--smbk-size-icon-sm16pxSize
space.inset.md--smbk-space-inset-mdcomfortable: 8pxcompact: 6pxchanges with densitySpacing
size.target.min--smbk-size-target-min24pxSize
size.24--smbk-size-2424pxSize
typography.label-sm--smbk-typography-label-sm-font-family--smbk-typography-label-sm-font-size--smbk-typography-label-sm-font-weight--smbk-typography-label-sm-line-height--smbk-typography-label-sm-letter-spacing--smbk-typography-label-sm-text-transformfontFamily: Geist, Geist Fallback, system-ui, sans-seriffontSize: 12pxfontWeight: 500lineHeight: 1.4letterSpacing: 0px

The quick brown fox

Typography
size.icon.xs--smbk-size-icon-xs12pxSize
color.action.brand.background-hover--smbk-color-action-brand-background-hover#a51d17Color
color.action.brand.border-hover--smbk-color-action-brand-border-hover#0000000dColor
elevation.raised--smbk-elevation-raisedlight: 0px 2px 8px 1px #373d431a, 0px 1px 2px 0px #373d431adark: 0px 2px 8px 1px #00000026, 0px 1px 2px 0px #00000026Elevation
color.action.brand.background-pressed--smbk-color-action-brand-background-pressed#761812Color
elevation.inset-strong--smbk-elevation-inset-stronglight: inset -1px 2px 2px 0px #373d4333dark: inset -1px 2px 2px 0px #0000004dElevation
color.action.brand.background-disabled--smbk-color-action-brand-background-disabledlight: #cc0d0d66dark: #cc0d0d80changes with themeColor
color.action.brand.border-disabled--smbk-color-action-brand-border-disabled#0000000dColor
color.action.brand.foreground-disabled--smbk-color-action-brand-foreground-disabled#ffffff4dColor
color.surface.neutral-subtle--smbk-color-surface-neutral-subtlelight: #373d431adark: #606a7533changes with themeColor
color.action.default.foreground--smbk-color-action-default-foregroundlight: #2d3237dark: #e7ebf0changes with themeColor
color.surface.hover--smbk-color-surface-hoverlight: #373d4326dark: #606a754dchanges with themeColor
color.action.default.background-pressed--smbk-color-action-default-background-pressedlight: #c4cdd8dark: #4e555echanges with themeColor
color.action.disabled.background--smbk-color-action-disabled-backgroundlight: #373d4314dark: #606a751achanges with themeColor
color.action.disabled.foreground--smbk-color-action-disabled-foregroundlight: #7c8692dark: #606a75changes with themeColor
color.action.outline.border--smbk-color-action-outline-borderlight: #c4cdd8dark: #373d43changes with themeColor
color.action.outline.foreground--smbk-color-action-outline-foregroundlight: #2d3237dark: #c4cdd8changes with themeColor
color.action.outline.background-hover--smbk-color-action-outline-background-hoverlight: #373d431adark: #606a751achanges with themeColor
color.action.outline.border-hover--smbk-color-action-outline-border-hoverlight: #9ba5b1dark: #4e555echanges with themeColor
color.action.outline.background-pressed--smbk-color-action-outline-background-pressedlight: #c4cdd8dark: #2d3237changes with themeColor
color.action.disabled.border--smbk-color-action-disabled-borderlight: #c4cdd8dark: #2d3237changes with themeColor
color.action.outline.foreground-disabled--smbk-color-action-outline-foreground-disabledlight: #9ba5b1dark: #606a75changes with themeColor
color.action.inverse.background--smbk-color-action-inverse-backgroundlight: #2d3237dark: #f3f5f8changes with themeColor
color.action.inverse.border--smbk-color-action-inverse-borderlight: #373d43dark: #f9fafbchanges with themeColor
color.action.inverse.foreground--smbk-color-action-inverse-foregroundlight: #f9fafbdark: #232527changes with themeColor
color.action.inverse.background-hover--smbk-color-action-inverse-background-hoverlight: #232527dark: #e7ebf0changes with themeColor
color.action.inverse.border-hover--smbk-color-action-inverse-border-hoverlight: #2d3237dark: #9ba5b1changes with themeColor
color.action.inverse.background-pressed--smbk-color-action-inverse-background-pressedlight: #181a1cdark: #c4cdd8changes with themeColor
elevation.inset--smbk-elevation-insetlight: inset 0px 0px 1px 0px #373d434ddark: inset 0px 0px 1px 0px #00000066Elevation
size.target.comfortable--smbk-size-target-comfortable44pxSize
Manifest
chip.manifest.json
{
  "name": "chip",
  "block": "smbk-chip",
  "summary": "A small selectable token — a filter, a choice, a person — that can carry an avatar and be removed.",
  "adapt": "css",
  "axes": {
    "tone": {
      "values": [
        "default",
        "brand",
        "outline",
        "inverse"
      ],
      "default": "brand",
      "description": "Which action family the chip draws from; default is a see-through gray that shows on every surface."
    },
    "size": {
      "values": [
        "md",
        "sm"
      ],
      "default": "md",
      "description": "The pill scale shared with the badge and the tag: 32 and 24 tall."
    }
  },
  "flags": {
    "selected": {
      "description": "The chip is currently chosen: pressed in, with a tick before its label. Given as true or false, the chip is a toggle and announces pressed or not pressed; left out, it is a plain button."
    }
  },
  "parts": [
    "tick",
    "avatar",
    "label",
    "remove"
  ],
  "figmaNodeId": "4253:1311"
}