Chip

Turns a filter on or off with a tap, like Food or This month.

Examples

Filter spending

Applied filters

Quick amounts

On remove

  • nonedefault

  • function

States

  • rest

  • hover

  • focus

  • disabled

Usage

When to use it
Use
A filter or topic that is on or off: Groceries, Vertical, Under $50.
Use
An applied filter the person removes with one press.
Use
Picking several tags from a short list.
Not for
Static metadata the person cannot act on. Use Badge.
Not for
Exactly one of a few. Use Segmented.
Not for
An option on a form that waits for a Save. Use Checkbox.

Rules

8 rules
Must
Wrap chips that share a question in role="group" with an aria-label. Because a screen reader otherwise reads a row of toggles with no question they answer.
Must
Set removeLabel to name each close button, such as "Remove Vertical". Because removeLabel defaults to "Remove", so every close button reads the same.
Must
Move focus to the next chip or the group after a removal. Because the close button unmounts with its chip and focus falls to the body.
Should
Say nothing is filtered when the last chip is removed instead of leaving a blank row.
Should
Use one to three words in sentence case; the label never wraps.
Never
Use a disabled Chip to show a status; use Badge for anything static. Because a disabled Chip is still announced as a toggle button, dimmed to fg-disabled.
Must
Put chips in a flex-wrap row; they never shrink or wrap their label. Because chips are whitespace-nowrap, so an unwrapped row overflows a 390px screen.
Never
Put your own button inside a Chip; onRemove already renders a sibling close button. Because a button inside the Chip's button is invalid HTML and its press also toggles the chip.

Accessibility

4 checks
Role button with aria-pressed true or false; the close button is a separate button.
Space and Enter toggle; Tab visits each chip and close button in order.
Chosen shows the wash, an olive edge and a check, so it reads without color.
Focus shows a 2px olive outline offset 2px.

Edge cases

6 edge cases
Long label
Never wraps; the chip is as wide as its text and overflows a narrow row.
Row in 160px
A flex-wrap row wraps; a no-wrap row overflows.
Right to left
The toggle and close button mirror with logical edges.
Zoom 200%
The text grows and the 32px height stays.
Touch
The chip is 32px tall, under 44px; leave 8px between chips.
Forced colors
A chosen chip paints with Highlight; the check follows the text color.

API

5 props
pressed, defaultPressed
boolean default false
onPressedChange
(pressed: boolean, details) => void
onRemove
() => void
removeLabel
string default 'Remove'
disabled
boolean default false

Tokens

15 tokens
--page
#ffffff
--line-strong
#cfcdc6
--fg
#0f0f0d
--control-sm
32px
--radius-control
999px
--surface
#f6f5f2
--accent-wash
#f5f9c4
--accent-line
#7c8700
--fg-disabled
#a6a49b
--fg-3
#6b6a63
--ring
var(--accent-line)
--line-focus
2px
--focus-offset
2px
--dur-instant
80ms
--ease-out
cubic-bezier(0.16, 1, 0.3, 1)

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.