Chip
Compact removable tag with tones, variants, sizes, an optional leading icon or avatar slot, and click-to-remove interactions. Perfect for filters, taggable inputs, and metadata pills.
Live Preview
Adjust the chip's tone, variant, size, and slots in real time. The right column mirrors the same configuration inside a ChipGroup.
1<Chip2 tone="brand"3 variant="subtle"4 size="md"5 onRemove={() => remove(id)}6>7 Design8</Chip>Installation
Install the Aidash Components package using your preferred package manager.
$ pnpm add @aidash/componentsImport
Import Chip and ChipGroup into your file.
import { Chip, ChipGroup } from '@/components/aidash/chip';Basic Usage
The simplest form: a static label pill.
1<Chip>Design</Chip>Tones
Six semantic tones cover neutral labels and status indicators.
1<Chip tone="default">Default</Chip>2<Chip tone="brand">Brand</Chip>3<Chip tone="success">Success</Chip>4<Chip tone="warning">Warning</Chip>5<Chip tone="danger">Danger</Chip>6<Chip tone="info">Info</Chip>Variants
Three visual weights: solid, subtle, and outline.
Solid
Subtle
Outline
1<Chip tone="brand" variant="solid">Brand</Chip>2<Chip tone="brand" variant="subtle">Brand</Chip>3<Chip tone="brand" variant="outline">Brand</Chip>Sizes
Three sizes to fit dense filter bars, standard forms, or hero contexts.
1<Chip size="sm">Small</Chip>2<Chip size="md">Medium</Chip>3<Chip size="lg">Large</Chip>With Icon
Pass a hugeicons icon module via the icon prop to prepend a small glyph.
1import { Tag01Icon, StarIcon, HeartIcon, CheckmarkCircle02Icon } from '@hugeicons/core-free-icons';2 3<Chip tone="brand" icon={Tag01Icon}>Featured</Chip>4<Chip tone="warning" icon={StarIcon}>Starred</Chip>5<Chip tone="danger" icon={HeartIcon}>Loved</Chip>6<Chip tone="success" icon={CheckmarkCircle02Icon}>Done</Chip>With Avatar
Pass any node to the avatar prop — the Chip wraps it in a rounded, size-matched container. Icon wins if both are provided.
1<Chip2 avatar={<div className="bg-brand-500/15 text-brand-500 text-[10px]">AL</div>}3>4 Ada Lovelace5</Chip>Removable
Pass onRemove to render a trailing X button. Wrap chips in AnimatePresence so the exit transition plays as items are removed.
1import { AnimatePresence } from 'framer-motion';2 3const [items, setItems] = useState(['Design', 'Engineering', 'Marketing']);4const remove = (v: string) => setItems((prev) => prev.filter((x) => x !== v));5 6<ChipGroup>7 <AnimatePresence>8 {items.map((item) => (9 <Chip key={item} tone="brand" onRemove={() => remove(item)}>10 {item}11 </Chip>12 ))}13 </AnimatePresence>14</ChipGroup>Clickable
Provide onClick to render the chip as a semantic <button>. Enter and Space activate it; Backspace / Delete trigger onRemove when both are set.
Clicks: 0
1<Chip tone="brand" onClick={() => handleSelect(id)}>2 Click me3</Chip>4 5{/* Combine onClick + onRemove — Backspace/Delete triggers remove */}6<Chip7 tone="success"8 variant="solid"9 icon={CheckmarkCircle02Icon}10 onClick={() => handleSelect(id)}11 onRemove={() => handleRemove(id)}12>13 Click or remove14</Chip>Disabled State
Disabled chips are dimmed and skip pointer + keyboard interaction.
1<Chip disabled>Default</Chip>2<Chip tone="brand" variant="solid" disabled>Solid</Chip>3<Chip tone="danger" variant="outline" disabled onRemove={() => remove()}>4 Removable5</Chip>Accessibility
Chip switches its host element and ARIA wiring based on the interactions you enable.
Semantic button vs. span
Providing onClick upgrades the root to <button type="button">. Purely decorative chips stay as <span>.
Remove button aria-label
The trailing X is its own <button> with a distinct aria-label (defaults to "Remove <text>") and stops click propagation so the parent chip doesn't also fire.
Keyboard: Backspace / Delete
When the chip is focused as a button, Enter / Space activate it and Backspace / Delete trigger onRemove.
Focus-visible outline
Interactive chips render a focus-visible ring using the brand token so keyboard users can see the focus target without adding noise for mouse users.
<Chip
tone="brand"
onClick={() => select(id)}
onRemove={() => remove(id)}
removeAriaLabel={`Remove tag ${label}`}
>
{label}
</Chip>
{/* Renders:
<button type="button" aria-disabled={undefined}>
...label...
<button aria-label="Remove tag Design">...</button>
</button>
*/}API Reference
Complete list of props for Chip and ChipGroup.
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | Chip label content. |
| tone | 'default' | 'brand' | 'success' | 'warning' | 'danger' | 'info' | 'default' | Semantic color tone. |
| variant | 'solid' | 'subtle' | 'outline' | 'subtle' | Visual variant. |
| size | 'sm' | 'md' | 'lg' | 'md' | Chip size. |
| icon | IconSvgElement | — | Leading hugeicons icon. Wins over avatar when both provided. |
| avatar | ReactNode | — | Leading avatar node (mutually exclusive with icon). |
| onClick | () => void | — | When provided, renders the chip as a <button>. |
| onRemove | () => void | — | When provided, renders a trailing X remove button. |
| disabled | boolean | false | Dim the chip and disable interaction. |
| removeAriaLabel | string | 'Remove ${text}' | Override the remove button's aria-label. |
| className | string | '' | Additional CSS classes. |
| Prop | Type | Default | Description |
|---|---|---|---|
| children* | ReactNode | — | Chips to lay out. |
| spacing | 'sm' | 'md' | 'lg' | 'md' | Gap between chips (gap-1 / gap-2 / gap-3). |
| className | string | '' | Additional CSS classes. |
<AnimatePresence> to opt in to exit transitions when items are removed. Without it the removal is instant.Related
Other components that work well alongside Chip.