Badge
Labels a status or a count in a short chip.
Installation
The CLI installs the Radix or Base UI file to match your project.
If your project doesn't have Wisty UI's theme yet, add it once with npx shadcn@latest add @wisty/cosmos. Until then, components keep shadcn's default look. Installation has the details.
When to use
Use it
- To label a record's status where people scan for it, like a stage in a table row or a state next to a page title.
- To show a short count or category next to a label: "3 new", "Beta", "Partner".
- To color a status by meaning with
success,warning,destructiveandinfo. The word in the label still carries the meaning. - To link a label to a filtered view, with
badgeVariants()on the link.
Don't use it
- For an action like Approve or Retry. Use Button.
- For a value people can remove, like a selected filter or a record picked in a lookup. Use Pill.
- For a message that needs a sentence or tells people what to do next. Use Alert.
- To flag a form error. Put the error text under the field, with Field.
- To switch between views. Use Tabs.
Usage
Pick a variant by meaning. An icon goes before or after the label as a direct child.
import { Badge } from "@/components/ui/badge"<Badge variant="success">Qualified</Badge>A link that should look like a badge takes badgeVariants() through cn(), as the As a link example shows. Without cn(), the outline and secondary borders lose to the base's transparent border.
Examples
Variants
Every `variant`, with `inverse`, `success`, `warning` and `info` on the second row.
With icon
An icon as a direct child of `Badge`, before the label on three badges and after it on Escalated.
As a link
Links to filtered list views, styled with `cn(badgeVariants())` on the anchor, with a hover color and focus ring.
API reference
Badge
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "secondary" | "destructive" | "outline" | "ghost" | "link" | "inverse" | "success" | "warning" | "info" | "default" | |
asChild | boolean | false | Renders the child element in its place, with the props merged onto it. |
Also takes every <span> (opens in a new tab) prop.
SLDS mapping
Badge is slds-badge, and the feedback variants are its slds-theme_* colors. secondary and outline both draw slds-badge_lightest, so they look the same. ghost and link have no SLDS counterpart: they're shadcn's, kept so shadcn code still compiles.
Known gaps:
- SLDS puts a start margin between adjacent badges (
.slds-badge + .slds-badge). Badge doesn't, so give the parent agap-2.
| Prop | Value | SLDS | Notes |
|---|---|---|---|
variant | default | slds-badge | |
variant | secondary | slds-badge_lightest | |
variant | outline | slds-badge_lightest | |
variant | destructive | slds-badge slds-theme_error | |
variant | ghost | none | Transparent, kept from shadcn. |
variant | link | none | Link-colored, kept from shadcn. |
variant | inverse (added) | slds-badge_inverse | |
variant | success (added) | slds-badge slds-theme_success | |
variant | warning (added) | slds-badge slds-theme_warning | |
variant | info (added) | slds-badge slds-theme_info |
Accessibility
- Write the status in the label. The feedback variants only change colors, and icons are hidden from assistive technology.
- Don't put
aria-labelon a plain badge. Aspanwith no role can't take a name, and axe reports it. Add hidden text instead:<Badge>3 <span className="sr-only">unread</span></Badge>. - A badge doesn't announce changes. If a count updates while someone's on the page and they need to know, render it inside a
role="status"region. - In Lightning Blue, the
defaultbadge's gray text on gray is below 4.5:1, the pair Salesforce's own badge uses. - In Cosmos dark, the
inversebadge's dark text on gray is below 4.5:1, the pair Salesforce's own inverse badge uses.
Responsive behavior
- A badge sizes to its content, never wraps and doesn't shrink in a flex row, so a long label makes it wider. To cap one, set a max width and truncate the text:
<Badge className="max-w-40"><span className="truncate">Enterprise renewal</span></Badge>. - Put
flex flex-wrap gap-2on the parent so a row of badges wraps.
Rules
- Don't wrap an icon or set its
size. The badge sizes only its directsvgchildren. - Don't add
onClickto a badge. Use Button for actions. - Never hard-code colors or sizes (
bg-green-100,rounded-full,text-[11px]). The tokens carry each theme. - A badge can be a link, but it can't contain one or any other control.
- Avoid
ghostandlink. Salesforce draws neither, so they look out of place next to other badges.