Badge
A compact label for status, counts, and categories. Single-element like Button; status variants are soft tints derived from semantic tokens, so they re-theme everywhere.
Installation#
Usage#
import { Badge } from "@/components/ui/badge"
export function Example() {
return <Badge>New</Badge>
}Playground#
The whole control set is derived from the component’s recipe: change a tone or add a size and this follows on its own. Note that dismissal isn’t a flag but a handler, so the trailing button exists exactly when onRemove does.
The tone. Soft fills for status, solid for emphasis.
Fully rounded instead of the control radius.
The house default for a status badge.
Adds a trailing dismiss button via onRemove.
<Badge>In review</Badge>Variants#
Status#
Soft status variants pair a tinted background (the status hue at /10) with a darker text counterpart and no border, so the fill carries the color while the label stays legible. Both derive from one semantic token (--success, --warning, --info), so they re-theme across all four themes.
Categorical#
Four extra hues for labeling categories, feature flags, and tags. All follow the same soft-tint pattern and re-theme across all four themes.
With dot#
The dot prop adds a leading status dot in the variant color - ideal for presence and at-a-glance state. The background is stripped so only the dot carries the color.
Toggling the dot#
Drive dot from state and the change animates: the dot grows in and pushes the label over, the tint gives way to the hairline, and the label settles on foreground. Turning it off plays the same thing in reverse, back to the tinted badge. A badge that never passes dot renders no dot at all.
Custom color#
When the color arrives with the data (a dispatch call code with its category hex, a team, a label a user picked), pass it as color. The variant still picks the treatment: any page-ground tone gives the soft tint, with the label pulled toward the theme's foreground so a pale yellow still reads; primary (or secondary) gives a solid fill whose ink is chosen from the color itself, near-black on a light fill and white on a dark one; outline draws the hairline in the color. With dot the dot takes it.
The ink is read from hex (#rgb, #rrggbb, with or without alpha) and rgb(); any other form (a named color, hsl(), a var()) paints fine but gets white ink, so prefer hex for solid badges. The same choice is exported as readableInk(color), returning "dark" or "light", for your own surfaces.
Sizes#
Pill#
Set pill for fully rounded edges - pairs well with dot and icon badges.
With icon#
Dismissible#
Pass onRemove to render a trailing dismiss button. Give each a descriptive removeLabel for screen readers.
As child#
Use asChild to render the badge styles on another element - e.g. a link - via Radix Slot.
API reference#
Badge
A single <span> that labels a status, count or category. Forwards all native <span> props; accepts className, merged last.
| Prop | Type | Default | Description |
|---|---|---|---|
| variant | "default" | "primary" | "secondary" | "outline" | "success" | "warning" | "info" | "destructive" | "purple" | "pink" | "teal" | "orange" | "overlay" | "overlayLight" | "default" | The fill: neutral, solid, outline, a soft status tint, a categorical hue, or a dark or light glass for media. |
| size | "sm" | "md" | "lg" | "md" | Padding, type and icon size. |
| pill | boolean | false | Fully rounded ends. |
| dot | boolean | - | A leading dot in the current color; the fill gives way to a hairline. Passing a boolean (even false) keeps the slot mounted, so flipping it animates. |
| color | string | - | Any CSS color. Paints the variant's treatment from it: a soft tint for the page-ground tones, a solid fill with a computed dark or white ink for primary / secondary, the hairline for outline; the dot takes it as is. Ignored by the overlay* fills. The root gets data-color and, when solid, data-ink (dark | light). The exported readableInk(color) returns that same pick. |
| onRemove | () => void | - | Renders a trailing dismiss button that calls it. |
| removeLabel | string | "Remove" | The accessible label of the dismiss button. Name the item ("Remove Design"). |
| asChild | boolean | false | Renders the badge styles onto its single child (Radix Slot), such as a link. Ignores dot and onRemove. |