Gesso
Components

Chip

Inline filter and selection chips with optional icon and dismiss.

Chip is the soft, rounded label for categories, filters, and selected values. Corners are fixed at the catalog --radius-scale-md step (8px) in the component — not rounded-control or rounded-md — so ICS pill buttons and xl boxes do not reshape chips.

By default chips read bg-secondary-subtle (--brand-secondary-subtle). Filled chips use text-fg (chrome ink). Outline uses border-primary-subtle text-primary — the soft / emphasis pair on the brand ramp.

For per-value categorical hues that must not follow the brand, see Category-colored tags below (or category colors in the data layer).

Badge is the sharper status mark (seven role variants, asChild). CircleBadge is the 8px dot. See Badge for those.

Chip is presentational — the root has no hover or focus ring. Only the dismiss control is interactive. For filter dropdowns with selected / open states, use Filter chip.

Variants

Three visual weights — default, outline, and ghost. All accept an optional leading icon via iconBefore (same slot pattern as Button). Switch Color in the sidebar (Washi / ICS) to see the brand remap.

Default
Outline
Ghost
With icon
Outline + icon

Brand coloring

Soft and emphasis are the chip pair. Soft fill (--brand-secondary-subtle) seats in chrome via --sys-soft so ink picks up paper temperature; chromatic prefabs pass soft through unchanged. Emphasis (--brand-primary-subtle) binds direct — lighter primary tint on the outline border.

LookSoft (fill)Emphasis (border)
Ink / dry--neutral-200 / --neutral-800--neutral-300 / --neutral-600
Washi--washi-blossom-soft--washi-wave-emphasis
ICS light--ics-orange-100--ics-violet-200
ICS dark--ics-orange-600--ics-violet-300

Atlas maps the same job to --secondary under [data-theme="ics"]. Dry Kit keeps secondary for the fill wash and puts soft on brand instead.

Dismissible (combobox / multi-select)

Pass onRemove to render a trailing dismiss control. The parent owns the list — typical pattern: map selected values to chips, filter state in onRemove.

Combobox-style selected values — each chip removes itself from the parent list via onRemove.

  • Design
  • Engineering
  • Product
import { Chip } from '@/registry/dry/ui/badge';

const [values, setValues] = useState(['Design', 'Engineering']);

<div className="flex flex-wrap gap-2">
  {values.map((value) => (
    <Chip
      key={value}
      onRemove={() => setValues((v) => v.filter((x) => x !== value))}
      removeLabel={`Remove ${value}`}
    >
      {value}
    </Chip>
  ))}
</div>

removeLabel overrides the default accessible name (Remove {children} when children is a string, otherwise Remove).

Category-colored tags

Grid select/status values use PropertyTag — same chip shape, categorical hue from the data layer (Badge tag variant + catChipStyle). A High option stays orange whether the brand primary is ink, wave, or violet.

Role Chip

Default
Outline
Ghost

Category

HighMediumDesign

Palette

grayredorangeambergreenbluepurplepink

catChipStyle in registry/data/lib/cat-colors.ts mixes --sys-cat-* into chroma-stripped --background and --foreground. Primitives (--cat-orange, etc.) keep their hue; system adds --chrome-chroma-tag so Washi warms tags slightly without recoloring them with the brand.

Token on the tagMix
fill30% --sys-cat-* into chroma-stripped --background
ink45% --sys-cat-* into chroma-stripped --foreground
hairline38% --sys-cat-* into chroma-stripped --background

Weights are tuned for WCAG AA (4.5:1) label contrast on the fill across every hue in light and dark, base/warm/cool chrome. Heavier anchor mixes (52 / 82 / 58) read fine by eye but land around ~2:1 on amber in the browser.

<PropertyTag color={option.color}>{option.label}</PropertyTag>

Disabled

disabled dims the chip and blocks interaction, including dismiss.

Disabled
Disabled dismissible

Props

PropTypeDefaultDescription
childrenReactNodeChip label.
variant"default" | "outline" | "ghost""default"default = soft + ink fg; outline = emphasis border + primary text; ghost = primary text only. No root hover.
iconBeforeComponentType<{ className?: string }>Leading icon (e.g. Phosphor). Sized to 14px.
onRemove() => voidWhen set, renders a dismiss button. Parent removes the chip from its collection.
removeLabelstringderivedaria-label for the dismiss button.
disabledbooleanfalseDisables the chip and dismiss control.
classNamestringExtra classes on the root.
...propsHTMLAttributes<HTMLDivElement>Forwarded to the root div (data-*, etc.).

Chip renders a <div> (not a <span>) so a dismiss <button> is valid inside the root.

Install

Ships with the badge registry item:

shadcn add @gesso/badge
import { Chip } from '@/components/ui/badge';

On this page