Chip
Interactive label pills for filtering, tagging, and selection. Four variants, five intents, five sizes, six rounded options, optional remove button, leading icon/avatar/status slots, and RTL support.
Installation
pnpm add @tessinaui/uiUsage
import { Chip, ChipGroup } from "@tessinaui/ui";<ChipGroup>
<Chip>Label</Chip>
<Chip selected>Selected</Chip>
<Chip onRemove={() => {}}>Removable</Chip>
<Chip leadingIcon={<Tag />}>With icon</Chip>
</ChipGroup>Playground
Showcase
Variants
| Variant | Description |
|---|---|
outline | Border + white background. Default. Matches Figma spec. |
soft | Filled with a subtle secondary background. No border. |
solid | Filled with the intent colour (or secondary for none). |
ghost | No border, no background. Minimal emphasis. |
API Reference
Chip
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "outline" | "soft" | "solid" | "ghost" | "outline" | Visual fill style |
intent | "none" | "error" | "warning" | "success" | "info" | "none" | Semantic colour — applied when selected |
size | "xs" | "sm" | "md" | "lg" | "xl" | "md" | Text size and padding |
rounded | "none" | "sm" | "md" | "lg" | "xl" | "full" | "full" | Border radius |
selected | boolean | false | Active/toggled state — fills with intent colour |
disabled | boolean | false | Disables interaction |
dir | "ltr" | "rtl" | "ltr" | Text direction |
leadingIcon | ReactNode | — | Icon before label (controlled by showLeadingIcon) |
leadingAvatar | ChipAvatarDef | — | Avatar before label — picks one leading slot |
leadingStatus | StatusVariant | — | Coloured status dot before label |
showLeadingIcon | boolean | true | Show or hide leadingIcon / leadingStatus |
trailingIcon | ReactNode | — | Icon after label (ignored when onRemove is provided) |
onRemove | (e: MouseEvent) => void | — | Renders an × remove button when provided |
onClick | MouseEventHandler | — | Click handler — typically used to toggle selected |
className | string | — | Extra classes on the root element |
ChipAvatarDef
| Field | Type | Description |
|---|---|---|
src | string | Avatar image URL |
initials | string | 1-2 char fallback when no src |
status | StatusVariant | Status dot on the avatar (online/away/busy/…) |
ChipGroup
Container that wraps multiple chips with consistent spacing.
| Prop | Type | Default | Description |
|---|---|---|---|
gap | "sm" | "md" | "lg" | "md" | Gap between chips (4px / 6px / 8px) |
wrap | boolean | true | Wrap chips to multiple lines |
dir | "ltr" | "rtl" | "ltr" | Text direction |
Leading Slot Priority
When multiple leading props are provided, the first match wins:
leadingAvatar(avatar always renders if defined)leadingStatus(status dot — requiresshowLeadingIcon !== false)leadingIcon(icon — requiresshowLeadingIcon !== false)
Remove Button
When onRemove is provided, the chip renders as two sibling <button> elements inside a pill container:
<Chip onRemove={(e) => removeTag(tag)}>
TypeScript
</Chip>The remove button fires onRemove and stops click propagation so it does not trigger onClick (the toggle handler).
Toggle Pattern
const [selected, setSelected] = useState(false);
<Chip
selected={selected}
onClick={() => setSelected((s) => !s)}
>
Filter
</Chip>Filter Group
const [active, setActive] = useState<string[]>([]);
function toggle(tag: string) {
setActive((prev) =>
prev.includes(tag) ? prev.filter((t) => t !== tag) : [...prev, tag]
);
}
<ChipGroup>
{tags.map((tag) => (
<Chip
key={tag}
selected={active.includes(tag)}
onClick={() => toggle(tag)}
>
{tag}
</Chip>
))}
</ChipGroup>Accessibility
- Renders as
<button type="button">witharia-pressedreflecting theselectedstate. - When
onRemoveis provided, the main area and remove button are separate focusable<button>elements — fully keyboard navigable. - The remove button has
aria-label="Remove". disabledappliespointer-events-noneandopacity-50to all interactive areas.- Touch targets meet WCAG 2.1 AA (≥ 44×44 px) at
md,lg,xlsizes viamin-h-[44px]. - Leading icon and trailing icon containers have
aria-hidden="true"— labels provide the accessible text.
Status
A small circular status indicator for user presence (online, away, busy, neutral) and feedback states (success, info, warning, error). Five sizes from 8 px to 24 px. Used as a standalone badge or embedded inside Avatar.
Shortcut
Keyboard shortcut badges for documenting and displaying key combinations. Includes a standalone Key component for individual keys and a Shortcut wrapper for combos with configurable separators and RTL support.