Badge
Small non-interactive tag. Three variants ship in the kit: Badge (solid label — default / secondary / outline / destructive / verified), StatusBadge (soft-tinted transaction/entity status with a filled icon: created / pending / succeeded / declined / refunded / inactive), and BadgeNumber (pill count — 8 / 12 / 99+). For anything clickable use Button.
Anatomy
- 1Badge (solid label)
inline-flex rounded-md px-2 py-0.5 text-xs font-semibold. Icons composed as children auto-size to 12px via [&>svg]:size-3. Variants: default (primary) / secondary / outline / destructive / verified (blue-500).
- 2StatusBadge (status pill)
Soft-tinted (color/15 bg + color/foreground text) with a filled Phosphor icon and a canonical label per status. Pass status='created|pending|succeeded|declined|refunded|inactive'; override children to change the label.
- 3BadgeNumber (count pill)
h-5 min-w-5 rounded-full for counts. Same variants as Badge. Use for notification bells, inbox counters, unread markers.
Variants
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="verified">
<SealCheck weight="fill" />
Verified
</Badge>With icons
<Badge>
<CheckCircle weight="light" />
Approved
</Badge>
<Badge variant="secondary">
Next
<ArrowRight weight="light" />
</Badge>Status map (StatusBadge)
Each status ships with a token color + filled Phosphor icon + default label. Override the label via children when the domain wording differs ('Approved' vs 'Succeeded').
Number
<BadgeNumber>8</BadgeNumber>
<BadgeNumber variant="secondary">12</BadgeNumber>
<BadgeNumber variant="outline">3</BadgeNumber>
<BadgeNumber variant="destructive">99+</BadgeNumber>Recipes
Ready-to-copy compositions covering the most common Yuno usages of this atom.
The canonical usage: StatusBadge inside a table cell to communicate a payment/transaction state at a glance. Use the domain wording via children when it differs from the default label.
| Transaction | Amount | Status |
|---|---|---|
| tx_a1b2 | $ 145.20 | Approved |
| tx_c3d4 | $ 89.00 | Pending |
| tx_e5f6 | $ 320.50 | Declined |
<Table>
<TableHeader>
<TableRow>
<TableHead>Transaction</TableHead>
<TableHead>Amount</TableHead>
<TableHead>Status</TableHead>
</TableRow>
</TableHeader>
<TableBody>
<TableRow>
<TableCell>tx_a1b2</TableCell>
<TableCell>$ 145.20</TableCell>
<TableCell><StatusBadge status="succeeded">Approved</StatusBadge></TableCell>
</TableRow>
<TableRow>
<TableCell>tx_c3d4</TableCell>
<TableCell>$ 89.00</TableCell>
<TableCell><StatusBadge status="pending" /></TableCell>
</TableRow>
<TableRow>
<TableCell>tx_e5f6</TableCell>
<TableCell>$ 320.50</TableCell>
<TableCell><StatusBadge status="declined" /></TableCell>
</TableRow>
</TableBody>
</Table>BadgeNumber pinned top-right of a bell/inbox IconButton via relative + absolute positioning. Cap at 99+ so it does not push the icon.
<div className="relative inline-block">
<Button variant="ghost" size="icon" aria-label="Notifications">
<BellSimple weight="light" />
</Button>
<BadgeNumber
variant="destructive"
className="absolute -right-1 -top-1 pointer-events-none"
>
8
</BadgeNumber>
</div>Solid Badge (outline / secondary) placed after a title to categorize a resource (Rule type, Plan tier, Environment). Keep to one tag per title so it does not become noise.
High-value BIN block
Fraud rule<div className="flex items-center gap-2">
<h3 className="text-lg font-semibold text-foreground">High-value BIN block</h3>
<Badge variant="outline">Fraud rule</Badge>
</div>verified variant with a leading SealCheck (fill) to mark an account, merchant or method as verified. Reserved for trust signals — never for status.
<div className="flex items-center gap-2">
<span className="text-sm font-medium text-foreground">Acme Merchants Ltd.</span>
<Badge variant="verified">
<SealCheck weight="fill" />
Verified
</Badge>
</div>Import
Copy this import line at the top of the file where you compose this atom.
import { Badge, BadgeNumber, StatusBadge } from "@/components/ui/badge";Props
Everything else from the underlying HTML or Radix primitive is forwarded via ...props.
| Prop | Type | Default | Description |
|---|---|---|---|
| Badge.variant | "default" | "secondary" | "outline" | "destructive" | "verified" | "default" | Solid label variants. Default = primary; verified = blue-500 (trust flag). |
| Badge.className | string | — | Merged. Icons composed as children auto-size to 12px via [&>svg]:size-3. |
| StatusBadge.status | "created" | "pending" | "succeeded" | "declined" | "refunded" | "inactive" | — | Required. Picks the color token + filled Phosphor icon + default label. |
| StatusBadge.children | React.ReactNode | — | Optional label override. Use when domain wording differs from the default (Approved vs Succeeded). |
| BadgeNumber.variant | "default" | "secondary" | "outline" | "destructive" | "default" | Same palette as Badge, without verified (counts do not signal trust). |
| BadgeNumber.children | React.ReactNode | — | The count. Cap display at 99+ so the pill does not push its neighbor. |
| badgeVariants / badgeNumberVariants / statusConfig | helpers | — | Exported for advanced composition. badgeVariants and badgeNumberVariants return the class string via CVA; statusConfig is the color+icon+label map keyed by status. |
When to use
- Transaction / entity status inside table rows (StatusBadge).
- Category or tag next to a title (Badge).
- Count on an IconButton (BadgeNumber — inbox, notifications, unread).
- Verified / trusted flag on an identity (Badge variant='verified').
When not to use
- Anything clickable — use Button or a chip with a close/action.
- Body text emphasis — use bold or a Callout.
- Blocking messages — use Dialog or AlertDialog.
- Persistent notices above a form — use Alert.
Usage
- Use the variant that matches meaning: success = approved, destructive = declined, verified = trusted identity.
- Keep the label to 1-2 words.
- For counts, cap at 99+ so the pill does not push its neighbor.
- For StatusBadge, override children only when the domain wording differs (Approved vs Succeeded).
- Don't stack more than 2 Badges next to a single title — it becomes noise.
- Don't make Badges clickable — use a Button variant instead.
- Don't invent a new status color — reach for one of the six StatusBadge tones or map yours to the closest one.
- Don't use variant='destructive' as decoration — reserve red for real declines or errors.
Related
Cross-links to atoms and patterns you may reach for next.