Chip
A compact interactive tag for toggling selection. Person chips pair an avatar with a name — the primary pattern for choosing who splits an expense. Category chips are label-only. State cycles between default (hairline border), active (ink fill), and settled (teal + strikethrough). Press state 0.97 on all chips.
Variants
Default — paper fill, warm hairline border. The person is available but not yet selected for this expense.
Active — ink fill, paper text. The person is included in the split. Ink is the "confirmed" surface.
Settled — teal-pale fill, teal border, strikethrough label. The person has paid their share and is done. The strikethrough is a visual celebration of completion — "all settled up."
Person chip — same states as above, but with an avatar leading the label. The tighter left padding (4px) keeps the avatar flush against the chip edge.
States
| State | Background | Border | Text | Transition |
|---|---|---|---|---|
| Default | --s-paper | --ink-line | --ink-body | — |
| Hover | --s-warm | --ink-mute | --ink | 140ms ease-out |
| Active | --ink | --ink | --s-paper | 140ms ease-out |
| Settled | --teal-pale | --teal | --teal + strikethrough | 140ms ease-out |
| Pressed | Unchanged | Unchanged | Unchanged | scale(0.97), 140ms |
| Disabled | Unchanged | Unchanged | 40% opacity | — |
On dark surfaces
On dark surfaces, default chips use --dark-elevated fill with --dark-border. Active inverts to paper-on-ink (the same as light). Settled uses a translucent teal fill with teal border. Add .on-dark to the parent container.
Anatomy
| Part | Element | Notes |
|---|---|---|
| Container | <button class="chip"> | Pill shape (--r-pill). Always a <button> — not a <div>. Handles all keyboard interaction natively. |
| Avatar | .avatar.avatar-xs (optional) | Only in .chip-person. 20px (-xs). aria-hidden="true" — the chip label names the person. |
| Label | Text node | Person's first name only. Sentence case. For category chips, keep it 1-2 words. |
Usage
Accessibility
<button> elements — not divs. Focusable via Tab, activated via Enter or Space. For a chip group that acts as multi-select, consider role="group" on the container with an aria-label describing the group.
aria-pressed="true". Settled chips should have aria-pressed="true" and aria-label="Rohan — settled" so the strikethrough state is announced. Never rely on the strikethrough text-decoration alone to communicate settlement.
aria-hidden="true" — the chip button itself carries the person's name as its text content. Screen readers don't need to announce both "P" (the initial) and "Priya" (the label).
Code
HTML
<!-- Label chip, default --> <button class="chip" aria-pressed="false">Aarav</button> <!-- Label chip, active --> <button class="chip chip-active" aria-pressed="true">Priya</button> <!-- Label chip, settled --> <button class="chip chip-settled" aria-pressed="true" aria-label="Rohan — settled">Rohan</button> <!-- Person chip, active --> <button class="chip chip-person chip-active" aria-pressed="true"> <span class="avatar avatar-xs avatar-coral" aria-hidden="true">P</span> Priya </button>
CSS classes
| Class | Purpose |
|---|---|
.chip | Base — pill shape, hairline border, paper fill, transitions, press state |
.chip-active | Ink fill — person is included in the split |
.chip-settled | Teal-pale fill + strikethrough — person has paid |
.chip-person | Modified padding to accommodate leading avatar |
Design tokens used
| Token | Value | Role |
|---|---|---|
--r-pill | 999px | Chip border radius |
--s-paper | #FBF8F0 | Default background |
--ink-line | #DDD2B8 | Default border |
--ink | #171513 | Active fill |
--teal | #0E7C66 | Settled border and text |
--teal-pale | #D6EAE2 | Settled fill |
--d-fast | 140ms | All transitions |
--ease-out | cubic-bezier(0.23,1,0.32,1) | Easing curve |