Skip to content
Protocore Design Systemv1.6.9

/// Inputs

Chip

An interactive filter toggle — mono uppercase ghost outline that inverts to the primary fill when selected.

import { Chip } from "@protocore/pds";
View as Markdown

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

KeysAction
Tab / Shift+TabMove focus onto / off the chip (and onto its × when present).
Space or EnterToggle 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 onDismiss to render a trailing × affordance (labelled by dismissLabel).
  • a11y: accessibilityState { selected, disabled }.
<Chip defaultSelected onSelectedChange={setActive}>Errors</Chip>

Chip props

PropTypeDefaultDescription
asChildbooleanfalseRender as the single child element (Radix `Slot`) instead of a `<button>`. The × affordance is unavailable in this mode.
classNamestring
defaultSelectedbooleanInitial selected state when uncontrolled.
dismissLabelstringRemoveAccessible 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.
selectedbooleanControlled selected state. Pair with `onSelectedChange`.
styleCSSProperties

Related

  • BadgeA static, sentence-case status indicator with a tone-tinted fill — never interactive, never color-only.
  • TagA static, as-typed metadata label in muted mono — optionally bordered or copy-on-click.
  • SegmentedControlCompact single-select toggle — a bordered row of mono uppercase segments where the active one inverts to a solid fill.
  • FilterBarA wrapping row of filter chips above a grid or list; selects one value or many, with an optional mono eyebrow.