/// Inputs
Chip
An interactive filter toggle — mono uppercase ghost outline that inverts to the primary fill when selected.
import { Chip } from "@protocore/pds";Basics
A Chip is a toggle. Use defaultSelected for uncontrolled state, or pair selected with onSelectedChange to control it. It exposes aria-pressed, so assistive tech announces it as a pressed button.
A filter set
The canonical use: a row of multi-select filters over a dataset. Each Chip owns its own selected state; the parent tracks which are active.
Dismissible
Pass onDismiss to add a trailing × affordance — handy for showing (and clearing) applied filters. The × is separately focusable and doesn't toggle the chip.
Chip vs Badge vs Tag vs Button
These four look adjacent but encode different things — the case-and-family contract keeps them distinct:
- Chip — *interactive*. Mono UPPERCASE, a ghost outline that inverts when selected,
aria-pressed. Use it to filter or toggle a view. - Badge — *static status*. Sentence-case sans on a tone tint, never clickable. Use it to show state (Live, Degraded, Pending).
- Tag — *static metadata*. As-typed mono, muted, no fill. Use it to label (a commit hash, a version, a key).
- Button — *one-shot action*. It doesn't hold a selected state; it *does* something when pressed.
Rule of thumb: if clicking it changes what's shown, it's a Chip; if it just *is* information, it's a Badge or Tag; if it *runs* something, it's a Button.
Do & don't
Do
- Use Chips for multi- or single-select filters over a list or grid.
- Keep labels to one or two mono words — "eu-central", "tier:1".
- Control the set from the parent when the selection drives a query.
- Add onDismiss to let people clear an applied filter in place.
Don't
- Don't use a Chip to show read-only status — that's a Badge.
- Don't use a Chip to trigger navigation or a one-shot action — that's a Link or Button.
- Don't rely on colour alone; the inverted fill plus aria-pressed carries the state.
- Don't mix Chips and Badges in the same row — the interactivity signal gets muddy.
Accessibility
| Keys | Action |
|---|---|
| Tab / Shift+Tab | Move focus onto / off the chip (and onto its × when present). |
| Space or Enter | Toggle the chip's selected state. |
| Enter / Space (on ×) | Dismiss the chip without toggling it. |
- Renders a `<button>` with `aria-pressed` reflecting the selected state.
- The dismiss × is a separate focusable control with its own `dismissLabel` (default "Remove").
- Controlled via `selected` + `onSelectedChange`; uncontrolled via `defaultSelected`.
- `asChild` is available, but the × affordance is not injected in that mode.
Mobile (React Native)
Preview. @protocore/pds-mobile ships the React Native sibling of Chip. It mirrors the web API where React Native allows; the package is a preview with no device-level QA yet, so pin it and expect small changes.
Import it from the mobile package (not @protocore/pds), inside a <PdsProvider> — there is no stylesheet, so style (a ViewStyle) replaces className and every value comes from the theme:
import { Chip } from "@protocore/pds-mobile";Parity with web. An interactive filter toggle built on Pressable (no :hover).
- Selected inverts to the primary fill on press, matching web; state is controllable via
selected/defaultSelected/onSelectedChange. - Pass
onDismissto render a trailing × affordance (labelled bydismissLabel). - a11y:
accessibilityState{ selected, disabled }.
<Chip defaultSelected onSelectedChange={setActive}>Errors</Chip>Chip props
| Prop | Type | Default | Description |
|---|---|---|---|
asChild | boolean | false | Render as the single child element (Radix `Slot`) instead of a `<button>`. The × affordance is unavailable in this mode. |
className | string | — | |
defaultSelected | boolean | — | Initial selected state when uncontrolled. |
dismissLabel | string | Remove | Accessible label for the × affordance. Defaults to `"Remove"`. |
onDismiss | (() => void) | — | When provided, renders a trailing × affordance; called (without toggling) when it is activated. |
onSelectedChange | ((selected: boolean) => void) | — | Fires with the next selected state whenever the chip is toggled. |
selected | boolean | — | Controlled selected state. Pair with `onSelectedChange`. |
style | CSSProperties | — |