Skip to content
Component installs need the registry setup— the Base UI shadcn project, the @vegastack namespace and the Cloudflare Access service token.
VegaStack Design

Chip

The one labelled pill — 10 decorative hues, two tiers, an optional selection rung, and a real 24px remove control.

Status
stable
Since
0.7.0
Accessibility pattern
non-interactive label + remove button

Last updated

UncategorizedB2BSaaSEnterprise
Status: OpenOwner

Install

Add Chip from the VegaStack registry. The CLI verifies the item's integrity hash before writing it.

pnpm dlx shadcn@latest add @vegastack/chip

The same command installs the registry items it composes: @vegastack/icon-button.

Usage

import { Chip } from "@/components/ui/chip";

<Chip hue="blue" onRemove={() => removeLabel("API")} removeLabel="Remove API">
  API
</Chip>;

Chip is the primitive behind Tag, FilterChip, ChipInput's chips and ComboboxChip. Reach for it directly when you need a labelled pill that none of those already is; reach for the named component when one of them fits, so the page keeps its vocabulary.

Anatomy

Chip is a compound component. Every exported part, with the data-slot it renders (generated from the canonical source):

Chip
ChipRemove — data-slot="chip-remove"

Examples

Two tiers

sm (28px) is the inline tag tier — tags in a record row, chips inside a field. md (32px) is the standalone control tier: it lines up with the Buttons, Inputs and Selects beside it, which is why an applied filter in a FilterBar uses it.

Inline · smControl · md

The 10-hue palette

Chips ride the --tag-{hue} token trios (-subtle fill, -text ink, base accent) — 10 chromatic hues plus the neutral chip, each AA-gated in both themes by the token contrast gate. Hue is a decorative label colour: it never signals status (that is Badge's five semantic intents).

neutralbluecyangreenlimeyelloworangeredpinkmagentapurple

Removable

onRemove mounts the remove control: a round, ghost IconButton whose real border box is 24×24, so the WCAG 2.5.8 target is the button itself and no clipping ancestor can shrink it. Always name what is being removed with removeLabel.

Design partnerPriorityEMEA

Selected

active promotes the neutral chip from its rest fill (surface-1) to the selection rung (surface-2) — the same step every selected surface in the system takes. It is ignored for a chromatic hue, whose tint already carries the meaning.

Composing another engine's chip

A chip whose behaviour belongs to another primitive keeps that primitive and wears this geometry through Base UI render. That is exactly how ComboboxChip works:

<Chip size="sm" active render={<Combobox.Chip />}>
  Design
  <ChipRemove aria-label="Remove Design" render={<Combobox.ChipRemove />} />
</Chip>

Chip vs Badge

BadgeChip
Voicestatus (5 semantic intents)label / selection (10 decorative hues)
Rootnot interactivenot interactive
Extrasdot, loading, animate-inremove control, selection rung

API Reference

Chip

PropTypeDefaultDescription
activebooleanfalseMarks the chip as an applied selection — the neutral chip takes the selection rung (surface-2) instead of its rest fill. Ignored for chromatic hues, whose tint already carries the meaning.
childrenReact.ReactNodeThe chip's content, laid out as a flex row. A part that can grow unboundedly is the caller's to wrap: <span className="min-w-0 truncate"> — Chip cannot know which of several children should give way.
data-slotstring'chip'Slot marker, for wrappers that compose Chip and want their own generated registry slot.
hueChipHue'neutral'Decorative hue from the tag palette. Never a status signal — that is Badge.
onRemove(() => void)Render a remove affordance and call this when it is activated. The control is a real 24×24 IconButton, never a pseudo-element hit area.
removeLabelstring'Remove'Accessible name for the remove control. Always name what is being removed.
renderuseRender.RenderProp<Record<string, unknown>>Replace the rendered <span> via Base UI render composition — how ComboboxChip puts this geometry on Base UI's own Combobox.Chip.
sizeChipSize'sm'Tier. sm is the inline tag tier (28px); md is the standalone control tier (32px) that lines up with Buttons and Inputs.

ChipRemove

ChipRemove takes every IconButton prop; aria-label is required. Render it yourself only when the remove control belongs to another engine — otherwise pass onRemove to Chip.

Accessibility

  • The chip root is not interactive and has no hover or pressed state. Nothing happens when you click it, so nothing pretends otherwise.
  • The remove control is a real 24×24 IconButton, so its pointer target is its own border box (WCAG 2.5.8) rather than an invisible pseudo-element a nested <button> would clip.
  • removeLabel names what is removed — “Remove SaaS”, not “Remove”.
  • Hue is decorative. Never let a chip colour be the only signal of status or meaning.
  • Wrap a growable label in <span className="min-w-0 truncate"> so a long value ellipsises instead of stretching the row.
ContractStates tested
Behaviourdefault, active, removable, disabled
Accessibilitylabeled, focus-visible
Visualdefault, hover, pressed, selected, disabled

Do / Don't

Do
Use one Chip for every labelled pill, and name every remove control after what it removes.
Don't
Hand-roll a pill with its own height, radius and a sub-24px remove button.

On this page