Chip
A chip family — Chip (display), ChoiceChip (radio-style single-select), and FilterChip (toggle-style multi-select). Modeled on Flutter Material's Chip API.
Chip (display)
The base Chip renders a static label with optional avatar, leading icon, and delete button.
Deletable chip
ChoiceChip (single-select)
ChoiceChip renders a <button role="radio"> for radio-style selection. Use inside ChipGroup type="single" or manage selected / onPressed yourself.
FilterChip (multi-select)
FilterChip renders a <button role="checkbox"> for toggle-style multi-selection. Use inside ChipGroup type="multiple" or manage state directly.
Active: events
Sizes
All three chip types share sm, md (default), and lg sizes.
Variants
filled-primary
Use filled-primary when a chip must assert primary brand prominence — for example, essence words on the Brand Workbench Elicit canvas, brand strategy surfaces, or marketing deck templates. It renders a saturated primary fill with --primary-text foreground and --shadow-sm depth.
Avoid using filled-primary for generic tags or filters; prefer default or outlined there to preserve the variant's signal weight.
Installation
npx visor add chipThis copies two files into your project:
components/ui/chip/chip.tsx— Chip, ChoiceChip, and FilterChip componentscomponents/ui/chip/chip.module.css— the styles
Usage
import { Chip, ChoiceChip, FilterChip } from '@/components/ui/chip/chip';
// Static display chip
<Chip label="React" />
// Deletable chip
<Chip label="Featured" onDeleted={() => removeTag('featured')} />
// Single-select (manage state yourself, or use ChipGroup)
<ChoiceChip
label="Compact"
selected={density === 'compact'}
onPressed={() => setDensity('compact')}
/>
// Multi-select toggle (manage state yourself, or use ChipGroup)
<FilterChip
label="Events"
selected={filters.includes('events')}
onPressed={() => toggleFilter('events')}
/>For managed selection state across a group, use the chip-group block.
API Reference
ChipProps
| Prop | Type | Default | Description |
|---|---|---|---|
variant | 'default' | 'outlined' | 'filled-primary' | 'default' | Visual variant. `default` — muted surface background. `outlined` — transparent with a border. `filled-primary` — saturated primary fill + primary-text foreground; use when the chip must carry primary brand prominence (essence chips, brand strategy surfaces). |
size | 'sm' | 'md' | 'lg' | 'md' | Controls chip height and font size. |
label | ReactNode | — | Label content. Falls back to children if omitted. |
avatar | ReactNode | — | Optional avatar rendered before the label. |
leadingIcon | ReactNode | — | Optional icon rendered before the label (after avatar). |
onDeleted | () => void | — | When provided, a delete button is shown and called on click. |
deleteLabel | string | 'Remove' | Accessible aria-label for the delete button. |
deleteIcon | ReactNode | — | Custom delete icon. Defaults to XIcon. |
className | string | — | Additional CSS class names merged onto the root element. |
...props | React.HTMLAttributes<HTMLDivElement> | — | All standard div attributes are forwarded to the root element. |
The component accepts all standard <div> HTML attributes.
ChoiceChipProps
| Prop | Type | Default | Description |
|---|---|---|---|
selected | boolean | false | Whether this chip is selected. |
onPressed | () => void | — | Called when the chip is pressed. |
value | string | — | Value identifier (used by ChipGroup). |
avatar | ReactNode | — | Optional avatar before the label. |
leadingIcon | ReactNode | — | Optional icon before the label. |
label | ReactNode | — | Label content (or use children). |
variant | "default" | "outlined" | "filled-primary" | "default" | Visual variant. |
size | "sm" | "md" | "lg" | "md" | Size. |
disabled | boolean | false | Disables the chip. |
FilterChipProps
| Prop | Type | Default | Description |
|---|---|---|---|
selected | boolean | false | Whether this chip is active. |
onPressed | () => void | — | Called when the chip is toggled. |
value | string | — | Value identifier (used by ChipGroup). |
leadingIcon | ReactNode | — | Optional icon before the label. |
label | ReactNode | — | Label content (or use children). |
count | ReactNode | — | Optional count pill after the label. |
countTone | "neutral" | "primary" | "neutral" | Tone for the count pill. |
selectedTreatment | "accent" | "neutral" | "accent" | Selected-state visual treatment. "accent" uses accent-tinted bg + link text (default). "neutral" uses --surface-card bg + neutral border + primary text; the count pill renders as a solid mint pill. Use in editorial/admin contexts to avoid accent bleed. |
variant | "default" | "outlined" | "filled-primary" | "default" | Visual variant. |
size | "sm" | "md" | "lg" | "md" | Size. |
disabled | boolean | false | Disables the chip. |
Accessibility
Chip(display) renders as a<div>. The delete button is a<button>witharia-label(defaults to"Remove").ChoiceChiprenders as<button role="radio" aria-checked>. Wrap in arole="radiogroup"container (or useChipGroup type="single") to provide group semantics.FilterChiprenders as<button role="checkbox" aria-checked>.ChipGroup type="multiple"wraps items inrole="group".- Keyboard:
Tabfocuses each interactive chip;Space/Entertoggles or activates. - Disabled chips use
disabledattribute andopacity— not hidden from screen readers.