Tag
Tag - An interactive pill component for selection, filtering, and multi-select scenarios.
Uses shared pill styling (identical to Badge) with interactive capabilities:
dismissibility, click handling, and keyboard support.
The outer element is polymorphic based on interactivity:
- onClick provided: <button>
- onDismiss only: <div> with dismiss <button>
- Both: <button> with dismiss <span role="button">
- Neither: <span> (presentational)
Usage
import { Tag, TAG_SIZES, TAG_TONES, TagEmphasis, TagProps, TagSize, TagTone } from "@desk/ui/components/tag";Best practices
Choose
Tagwhen the chip is interactive (selection/filter/dismiss); for a display-only status label or count useBadge, and for a bare colour dot useDot.The outer element is derived from your handlers — pass
onClickto make it a<button>and/oronDismissto reveal the "Remove" control; without either it renders an inert<span>, so don't wrap it in your own button.Set at most one leading visual —
loading>imageUrl>dot>icon(in that precedence); pass a Lucide component toicon(not<Icon/>), andimageUrlrenders a circular<img alt="">, so keep it decorative.When
onDismissis set, Backspace/Delete also removes the tag while it's focused — don't bind your own conflicting key handler.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
| children | React.ReactNode | ||
| disabled | boolean | Disabled state | |
| size | ResponsiveValue<PillSize> | "base" | Tag size — a single token or a per-breakpoint object like
|
| dismissIcon | React.ReactNode | Custom dismiss icon (defaults to X) | |
| dot | boolean | "neutral" | "brand" | "danger" | "warning" | "success" | "info" | Leading status dot: | |
| hideDismiss | boolean | Hide dismiss button even when onDismiss is provided | |
| icon | LucideIcon | React.ComponentType<React.SVGProps<SVGSVGElement>> | Leading icon | |
| imageUrl | string | Leading circular thumbnail image | |
| loading | boolean | Show loading spinner (replaces leading visual) | |
| onClick | React.MouseEventHandler<HTMLButtonElement> | Click handler — makes the whole tag a button | |
| onDismiss | (event: React.MouseEvent | React.KeyboardEvent) => void | Dismiss handler — shows dismiss button | |
| tone | "neutral" | "brand" | "danger" | "warning" | "success" | "info" | null | undefined | ||
| radius | "rounded" | "square" | "full" | null | undefined | ||
| emphasis | "outline" | "solid" | "ghost" | "soft" | "transparent" | null | undefined | ||
| asInput | boolean | null | undefined | Input-style chip: white bg + subtle shadow (unselected state). |
Also exports
- const
TAG_SIZES - const
TAG_TONES - type
TagEmphasis - interface
TagProps - type
TagSize - type
TagTone