Chip
Pills the user picks or removes: filters, a single choice, or values they entered.
Preview
Installation
pnpm add @syntara/react @syntara/tokensimport { ChipGroup, Chip } from '@syntara/react';Usage
import { Chip, ChipGroup } from '@syntara/react';
export function Filters() {
return (
<ChipGroup label="Show" defaultSelectedKeys={['sponsored']}>
<Chip id="sponsored" count={3}>Sponsored</Chip>
<Chip id="discounted" count={2}>Discounted</Chip>
<Chip id="consults" count={4}>Consults</Chip>
</ChipGroup>
);
}Examples
Choice
mode="choice": exactly one on, like a period picker that wraps.
Input
mode="input": entered values with a remove button; Delete or Backspace removes the focused chip.
Icons and avatars
A leading icon gives way to the check when selected; an avatar is covered by a check disc.
Sizes and one row
md (the control height) and sm, and wrap={false} for a single row that scrolls, with a disabled chip.
Badge, Tag, PersonChip or Chip
Badge = a state or count. Tag = a static attribute. PersonChip = a person. Chip = something the user picks or removes.
State or count
Attribute
A person
Pick or remove
Accessibility
| Keys | Action |
|---|---|
| Tab | Moves focus into the group (to the last focused chip), then (input mode) to that chip's remove button, then out. |
| ArrowLeftorArrowRight | Moves between chips (flipped in RTL). Disabled chips are skipped. |
| HomeorEnd | First / last chip. |
| SpaceorEnter | filter: turns the focused chip on or off. choice: selects it (the selected chip stays on). |
| DeleteorBackspace | input: removes the focused chip. |
- A React Aria TagGroup: role="grid" named by the label (or aria-label), each chip a row with aria-selected in filter and choice modes; filter mode sets aria-multiselectable.
- A chip's accessible name is its label plus its count ("Sponsored 3"), in the user's number format.
- Selection isn't carried by colour alone: selected chips turn medium weight, filter chips show a check, and forced-colours mode draws a Highlight edge.
- Remove buttons are named "Remove <label>" in the user's language and keep a 24px target at every size and density.
- Icons, avatars and the check are decorative (aria-hidden or alt="").
- Motion (pop-in, press spring, check draw-in, the check slot opening) is off with reduced motion; colours and the check still fade.
Guidelines
Do
- Use filter chips to narrow a list, choice chips for one option among a few, input chips for values the user typed or picked.
- Keep labels to one to three words; add a count when it helps people choose.
- Use wrap={false} for a filter row on narrow screens, and keep the first chips the most used.
Don’t
- Don't use a Chip for a status or count on its own (Badge), a static attribute (Tag) or a person (PersonChip).
- Don't use chips to navigate between pages; use Tabs or links.
- Don't mix modes in one group or put more than about ten chips in a row.
API reference
ChipGroup
modefilterdefaultchoiceinput
filter = any number on (multiple selection) with a check on selected chips; choice = exactly one on (single selection, can't be emptied); input = removable values, not selectable (needs onRemove).
labelReactNodeVisible label above the chips. Without it, pass aria-label or aria-labelledby.
sizesmmddefault
md is the control height (40px comfortable, 32px compact), the same as a Button or TextField; sm is one 8px step smaller.
wrapbooleanWrap onto more lines, or (false) keep one row that scrolls sideways.
Default
trueselectedKeys / defaultSelectedKeys'all' | Iterable<Key>Controlled or initial selection (filter and choice modes).
onSelectionChange(keys: Selection) => voidCalled when chips are turned on or off.
onRemove(keys: Set<Key>) => voidinput mode: called with the keys to remove (the remove button, Delete or Backspace).
disabledKeysIterable<Key>Chips that can't be focused, toggled or removed.
itemsIterable<T>Items for a dynamic collection; children is then a function that renders one Chip.
renderEmptyState() => ReactNodeShown when there are no chips (e.g. every input chip was removed).
childrenRequiredReactNode | (item: T) => ReactNodeChip elements.
Chip
idRequiredKeyThe chip's key in selection and onRemove.
childrenRequiredReactNodeThe label: one to three words.
iconReactNodeLeading icon from @syntara/icons. Decorative. In filter mode the check takes its place when selected.
avatarReactNodeA leading Avatar (pass alt=""). Sized to the chip; in filter mode a brand check disc covers it when selected.
countnumberA quiet trailing number, formatted for the locale and read as part of the chip's name ("Sponsored 3").
textValuestringPlain-text name when children isn't a string. The count is appended.
isDisabledbooleanDisables this chip (same as listing it in disabledKeys).
Default
false
Tokens
The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.
- Colour13
surface.defaultsurface.selectedsurface.sunkentext.defaulttext.subtletext.brandtext.disabledborder.defaultborder.strongborder.subtleaction.primary.bgaction.primary.fgfocus.ring- Type6
font.bodyfont.size.smfont.tracking.smfont.weight.regularfont.weight.mediumline-height.snug- Space and size6
control-heightspace.1space.2space.4space.6icon.stroke- Shape1
radius.pill- Depth3
hairlineshadow.raisedshadow.highlight- Motion5
motion.duration.fastmotion.duration.springmotion.springmotion.easingmotion.easingOut