Tag
A compact label for categorizing content. Five tonal variants, three sizes, and an optional close control for removable tags.
Playground
<Tag>Design</Tag>Preview
A single Tag renders an inline span. Pass onClose to append the remove button.
<Tag>Primary</Tag>
<Tag variant="secondary">Secondary</Tag>
<Tag variant="outline" onClose={() => {}}>
Removable
</Tag>Installation
npx shadcn@latest add https://espresso-base-ui.vercel.app/r/tag.jsonUsage
import { Tag } from "@/components/ui/tag"<Tag variant="secondary" size="sm" onClose={() => remove(id)}>
Design
</Tag>Variants
variant sets the tone: primary, secondary, outline, ghost and destructive – each with hover, focus-visible and active states.
<Tag variant="primary">Primary</Tag>
<Tag variant="secondary">Secondary</Tag>
<Tag variant="outline">Outline</Tag>
<Tag variant="ghost">Ghost</Tag>
<Tag variant="destructive">Destructive</Tag>Sizes
Three sizes: sm (20px), default (24px) and lg (28px). The outline variant trims 2px off each height to account for its outer shadow ring.
<Tag size="sm">Small</Tag>
<Tag size="default">Default</Tag>
<Tag size="lg">Large</Tag>Removable
With onClose the tag becomes focusable and shows a trailing remove button – click it, or focus the tag and press Backspace or Delete.
const [tags, setTags] = useState(["React", "Next.js", "TypeScript"])
{tags.map((tag) => (
<Tag
key={tag}
variant="secondary"
onClose={() => setTags(tags.filter((t) => t !== tag))}
>
{tag}
</Tag>
))}Disabled
disabled mutes the colors, blocks pointer events, hides the close button from assistive tech and removes the tag from the tab order.
<Tag variant="primary" disabled onClose={() => {}}>
Primary
</Tag>
<Tag variant="outline" disabled onClose={() => {}}>
Outline
</Tag>
<Tag variant="destructive" disabled onClose={() => {}}>
Destructive
</Tag>API reference
Tag renders a span and accepts className plus standard span props. The exported TagProps type covers the full signature.
Tag
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "primary" | "secondary" | "outline" | "ghost" | "destructive" | "primary" | Tone – filled primary/destructive surfaces, a soft secondary, a bordered outline, or a transparent ghost. |
| size | "sm" | "default" | "lg" | "default" | Height, padding, radius and type scale. Outline tags run 2px shorter per size to offset the shadow ring. |
| onClose | () => void | – | Renders the trailing remove button and makes the tag focusable. Called on click or on Backspace/Delete while the tag has focus. |
| disabled | boolean | false | Disables interaction: sets aria-disabled and data-disabled, blocks pointer events and removes the tag from the tab order. |
Accessibility & styling hooks
A removable tag takes tabIndex=0 so keyboard users can reach it and delete it with Backspace or Delete; the close control renders role="button" with aria-label="Remove". Disabled tags expose aria-disabled. The root carries data-slot="tag" and reflects its props as data-variant, data-size and data-disabled; the close button is data-slot="tag-close" – target these from CSS for app-level overrides.
The tagVariants cva helper is also exported for building custom tag-shaped surfaces with the same classes:
import { tagVariants } from "@/components/ui/tag"
<span className={cn(tagVariants({ variant: "outline", size: "sm" }))}>
...
</span>