Skip to content
Cloaked Design SystemControls

Chip

A compact pill in one of four shapes: selectable, command, removable, or readonly. Never more than one.

Implementation preview
COMPLETE STORYBOOK REFERENCE

Every example. In one place.

Explore every named example, including states, compositions, and theme variants.

6 stories
SELECTED EXAMPLE

Playground

Open controls
Playground selectedOpen canvas
Example sourcepackages/design-system/src/components/controls/Chip/Chip.stories.tsxExport Playground

Implementation preview Local Storybook build 0.2.0-preview.1. Source specification status does not approve this runtime.

Stories + source JSON ↗

Local specification source status: preview. Implementation preview pending sign-off.

A compact pill in one of four shapes: selectable, command, removable, or readonly. Never more than one.

Design-owned component contract ↗Version 0.2.0-preview.1 · Implementation preview pending sign-off
Implementation API 1 entry point · source-derived preview

Read the actual callable API and preserve its composition constraints. Each union branch is a complete alternative; props marked forbidden cannot be supplied.

import { Chip } from '@cloakedinc/design-system';
ChipChipProps

packages/design-system/src/components/controls/Chip/Chip.tsx:121

Props must satisfy one complete branch; a forbidden prop cannot be supplied.

SelectableChipProps
PropTypePresenceNotes
onPress() => voidRequiredFires on tap. Its presence is what makes the root a button.
selectedbooleanRequiredSelected state, exposed as `aria-pressed`.
onRemoveneverForbiddenUnavailable here: a selectable chip cannot also be removable.
removeLabelneverForbiddenUnavailable here: there is no remove affordance to name.
ariaLabelneverForbiddenUnavailable here: the visible label names a toggle whose state `aria-pressed` carries.
busyneverForbiddenUnavailable here: only a removable chip has an in-flight removal to report.
childrenReact.ReactNodeRequired
sizeChipSizeRequiredHeight and padding tier. `sm` suits inline value tokens, `md` filter rows.
disabledboolean | undefinedOptionalBlocks press and remove alike, and dims the chip.
leadingReact.ReactNodeOptionalOptional leading visual, usually an `Icon`, `Avatar`, or `SFIcon`.
hapticHapticFeedback | undefinedOptionalHaptic feedback for successful presses. Defaults to `true` (`selection`).
classNamestring | undefinedOptional
styleReact.CSSProperties | undefinedOptional
testIdstring | undefinedOptionalSelector for the chip. A removable chip's × derives `${testId}-remove` from it.
CommandChipProps
PropTypePresenceNotes
onPress() => voidRequiredFires on tap. Its presence is what makes the root a button.
ariaLabelstring | undefinedOptionalReplaces the visible label as the accessible name when the label alone lacks context.
selectedneverForbiddenUnavailable here: a command has no selected state. Pass `selected` to get a toggle.
onRemoveneverForbiddenUnavailable here: a command chip cannot also be removable.
removeLabelneverForbiddenUnavailable here: there is no remove affordance to name.
busyneverForbiddenUnavailable here: only a removable chip has an in-flight removal to report.
childrenReact.ReactNodeRequired
sizeChipSizeRequiredHeight and padding tier. `sm` suits inline value tokens, `md` filter rows.
disabledboolean | undefinedOptionalBlocks press and remove alike, and dims the chip.
leadingReact.ReactNodeOptionalOptional leading visual, usually an `Icon`, `Avatar`, or `SFIcon`.
hapticHapticFeedback | undefinedOptionalHaptic feedback for successful presses. Defaults to `true` (`selection`).
classNamestring | undefinedOptional
styleReact.CSSProperties | undefinedOptional
testIdstring | undefinedOptionalSelector for the chip. A removable chip's × derives `${testId}-remove` from it.
RemovableChipProps
PropTypePresenceNotes
onRemove() => voidRequiredFires from the remove button only, never from the chip body.
removeLabelstringRequiredAccessible name for the remove button. Name the value, as in `Remove sriram@example.com`.
busyboolean | undefinedOptionalShows a spinner in place of the remove icon and blocks the button while its removal is in flight.
onPressneverForbiddenUnavailable here: the remove button owns the only focus stop.
selectedneverForbiddenUnavailable here: a removable value has no selected state.
ariaLabelneverForbiddenUnavailable here: the remove button carries the accessible name, via `removeLabel`.
childrenReact.ReactNodeRequired
sizeChipSizeRequiredHeight and padding tier. `sm` suits inline value tokens, `md` filter rows.
disabledboolean | undefinedOptionalBlocks press and remove alike, and dims the chip.
leadingReact.ReactNodeOptionalOptional leading visual, usually an `Icon`, `Avatar`, or `SFIcon`.
hapticHapticFeedback | undefinedOptionalHaptic feedback for successful presses. Defaults to `true` (`selection`).
classNamestring | undefinedOptional
styleReact.CSSProperties | undefinedOptional
testIdstring | undefinedOptionalSelector for the chip. A removable chip's × derives `${testId}-remove` from it.
ReadonlyChipProps
PropTypePresenceNotes
onPressneverForbiddenUnavailable here: a readonly chip has no press. Add `onPress` to make it interactive.
selectedneverForbiddenUnavailable here: a readonly chip has no selected state.
onRemoveneverForbiddenUnavailable here: a readonly chip cannot be removed. Add `onRemove` to make it removable.
removeLabelneverForbiddenUnavailable here: there is no remove affordance to name.
ariaLabelneverForbiddenUnavailable here: the visible label is the whole accessible name.
busyneverForbiddenUnavailable here: only a removable chip has an in-flight removal to report.
childrenReact.ReactNodeRequired
sizeChipSizeRequiredHeight and padding tier. `sm` suits inline value tokens, `md` filter rows.
disabledboolean | undefinedOptionalBlocks press and remove alike, and dims the chip.
leadingReact.ReactNodeOptionalOptional leading visual, usually an `Icon`, `Avatar`, or `SFIcon`.
hapticHapticFeedback | undefinedOptionalHaptic feedback for successful presses. Defaults to `true` (`selection`).
classNamestring | undefinedOptional
styleReact.CSSProperties | undefinedOptional
testIdstring | undefinedOptionalSelector for the chip. A removable chip's × derives `${testId}-remove` from it.

Only explicit destructured parameter initializers are extracted. Other runtime defaults remain in implementation source.

Overview

A compact pill in one of four shapes. A selectable chip takes onPress with selected. A command chip takes onPress alone. A removable chip takes onRemove. A readonly chip takes neither, for a locked member of a chip set. Reach for Tag when the pill is a standalone marker or status label, and Dropdown for a trigger that opens a menu.

The shapes are different elements

This is the reason Chip and Tag are separate components, and the reason press and remove cannot be combined:

ShapeElementFocus stops
selectable<button aria-pressed>1
command<button>1
removable<span> with a nested remove <button>1
readonly<span> with no focus stop0
press+removewould need a <button> inside a <button>2

ChipProps is a discriminated union, so the last row cannot be written. Passing onPress and onRemove together is a type error rather than a runtime surprise.

selected is what separates the first two rows. A chip that reports aria-pressed="false" forever tells assistive technology it is an unselected member of a selection set — wrong for a chip that just opens an explainer. Omit selected and the attribute goes away with it.

Use when

size is sm for inline value tokens and md for filter rows. disabled sets the native disabled attribute and dims the chip. removeLabel is required on a removable chip: the × carries no visible text, so a generic default would ship a row of buttons all announcing the same thing.

Put a set in a ChipGroup

A bare row of chips reads to assistive technology as loose controls with no relationship. ChipGroup gives the set an accessible name and owns the row layout, including the wrap and scroll behavior.

Usage by variant

ChoiceUse whenAvoid when
Job: onPress + selectedA filter toggle where selected marks the active option — website filters, feedback options.Combining with onRemove. A trigger that opens a menu is a Dropdown, not a Chip.
Job: onPress aloneA one-off command — a risk chip that opens an explainer. ariaLabel names it when the visible label is not a complete phrase.A member of a selection set. Pass selected there so the toggle state is announced.
Job: onRemoveA removable value token — entered emails, phones, and addresses in the data-removal profile, where the × selector suffixes the chip testId with -remove.A filter — a removable chip is an entered value, not a toggle.
Job: no handlerA readonly, locked member of a chip set — the protected primary name sitting inline with removable name chips.A standalone marker or status label. Use a Tag there.

Do and don’t

GuidanceExample
DoGive a chip onPress, or give it onRemove, or leave both off for a readonly member.
DoPass selected only when the chip really is a toggle.
DoUse a readonly chip for a locked value inside a chip set, like the primary name in a value list.
Don’tReach for a readonly Chip as a standalone marker or status label. That is a Tag.

Component specification

$schema../../../specs/component-spec.schema.json
Parts
Id
container
Label
Container
Description
A button for a selectable or command chip, a span for a removable or readonly one. Owns size, selected, and disabled.
Required
true
Id
leading
Label
Leading visual
Description
Optional icon or avatar before the value.
Id
content
Label
Content
Description
Visible value or filter label.
Id
remove-action
Label
Remove action
Description
The independently named button on a removable chip, and its only focus stop.
Allowed Design Choices
Variants
Selectable
Label
Selectable
Description
Toggles its own state. Renders a button carrying aria-pressed.
Command
Label
Command
Description
Runs a one-off action. Renders a button with no aria-pressed.
Removable
Label
Removable
Description
Holds a value the user can dismiss. Renders a span with a nested remove button.
Readonly
Label
Readonly
Description
A locked member of a chip set. Renders a span with no remove button and no focus stop.
Sizes
Sm
Label
Small
Md
Label
Medium
Variants
Id
selectable
Label
Selectable
Description
onPress with selected. One focus stop, on the chip itself.
Platforms
  • ios
  • android
  • web
Id
command
Label
Command
Description
onPress without selected, plus an optional ariaLabel. One focus stop, on the chip itself.
Platforms
  • ios
  • android
  • web
Id
removable
Label
Removable
Description
onRemove. One focus stop, on the remove affordance.
Platforms
  • ios
  • android
  • web
Id
readonly
Label
Readonly
Description
Neither onPress nor onRemove. Renders a span with no focus stop.
Platforms
  • ios
  • android
  • web
Sizes
Id
sm
Label
Small
Description
24-unit inline value token.
Id
md
Label
Medium
Description
32-unit filter or standalone value chip.
Measurements
Id
small-min-height
Label
Small chip minimum height
Kind
exact
Token
--cds-size-24
Value
24
Unit
px
Applies To
  • container
  • sm
Id
medium-min-height
Label
Medium chip minimum height
Kind
exact
Token
--cds-size-32
Value
32
Unit
px
Applies To
  • container
  • md
Id
medium-content-gap
Label
Medium content gap
Kind
exact
Token
--cds-space-8
Value
8
Unit
px
Applies To
  • leading
  • content
  • trailing
  • remove-action
  • md
Layout
Alignment
All visible parts align on the pill center line and the container hugs its content.
Flow
Optional leading visual, content, then the remove action on a removable chip.
Notes
  • Assign exactly one shape: selectable, command, removable, or readonly.
  • Use readonly for a locked member of a chip set, and Tag for a standalone marker or status label.
  • Use Dropdown for a trigger that opens a menu.
  • Put a set in a ChipGroup rather than a bare row.
Typography And Color
Typography
Label
Chip content
Description
Use body-small text at both chip sizes.
Token
--cds-type-body-small-size
Colors
Label
Default surface
Description
Use the semantic input container.
Token
--cds-input-container
Label
Selected surface
Description
Use the inverse background for selected filters.
Token
--cds-bg-inverse
Label
Selected content
Description
Use inverse text on the selected inverse surface.
Token
--cds-text-inverse
Label
Content
Description
Use primary text emphasis for the represented value.
Token
--cds-text-primary
Label
Remove action
Description
Use secondary text emphasis for the remove icon.
Token
--cds-text-secondary
States
Id
default
Label
Default
Description
Shows the neutral pill treatment.
Id
selected
Label
Selected
Description
Inverse fill and inverse text on a selectable chip, exposed as aria-pressed.
Id
pressed
Label
Pressed
Description
Temporary press feedback on a selectable or command chip.
Id
disabled
Label
Disabled
Description
Sets the native disabled attribute and dims the chip.
Id
removing
Label
Removing
Description
On a removable chip, shows a spinner in place of the remove icon and blocks the remove button while its removal is in flight, exposed as aria-busy.
Behavior
Label
Selectable press
Description
Invoke onPress on tap and expose the pressed state. The root is a real button, so activation is native.
Label
Command press
Description
Invoke onPress on tap without reporting any selection state. Use this shape when the chip runs a one-off action, such as opening an explainer.
Label
Remove
Description
Invoke onRemove only from the independently labelled remove action.
Label
One shape per chip
Description
A chip is exactly one of selectable, command, removable, or readonly. The props are a discriminated union, so onPress and onRemove cannot be combined (two focus stops would require a button inside a button), selected is what picks selectable over command, and a chip with neither handler is readonly.
Label
Readonly member versus a standalone marker
Description
A readonly chip is a locked member of a chip set, so it stays in the chip family alongside its removable siblings. A standalone marker or status label is a Tag, and a pill that opens a menu is a Dropdown.
Accessibility
Label
Selectable semantics
Description
A selectable chip is a button carrying aria-pressed and the native disabled attribute.
Label
Command semantics
Description
A command chip is a button with no aria-pressed, because a permanent unpressed toggle state misreports a one-off action. Give it ariaLabel when the visible label is not a complete name.
Label
Removable semantics
Description
The body of a removable chip takes no focus. Its remove button is the only focus stop.
Label
Readonly semantics
Description
A readonly chip is a span with no role and no focus stop, so it is announced as text alongside its interactive siblings.
Label
Remove name
Description
Every remove action carries a value-specific accessible label and a stable test identifier. removeLabel is required, so there is no generic fallback to fall back to.
Label
Grouping
Description
Put a set of chips in a ChipGroup so they are announced as one group.
Content Adaptation
Label
Concise values
Description
Keep chip labels short enough to remain scannable in wrapping rows.
Label
Value-specific removal
Description
Name remove actions with the represented value or category when context is not obvious.
Motion Haptics
Motion
Label
Press feedback
Description
Use subtle opacity and scale feedback and remove scale under reduced-motion preferences.
Haptics
Label
Successful interaction
Description
Request the selection haptic after an enabled press or removal.
Platform Differences
Platforms
  • web
Description
Web renders no focus ring and no keyboard activation handler for either shape.
Rationale
The only consumers are a touch iOS WKWebView and a harness previewing that same UI, so a keyboard affordance here would be dead code.
Implementation preview

This design-owned implementation is ready to try and review. It does not establish product approval. Imported specifications retain their original review status.

Inspect version 0.2.0-preview.1