Badge

A small, inline status label for conveying counts, states, or categories. Supports six visual variants and optional icon slots via data-[icon] child styling.

Anatomy

A single <Badge> renders as a <span> via useRender. The variant prop controls visual style. SVG children are automatically sized to size-3 and aligned inline.

Label
renders as <span>variant="default"SVG auto-sized

Variants

Seven variants cover the full semantic range from primary emphasis to subtle decoration.

variant="default"
Default

Primary emphasis. Counts, active states.

variant="secondary"
Secondary

Neutral tone. Categories, tags.

variant="destructive"
Destructive

Error or critical status.

variant="success"
Success

Confirmed or valid status. Green tone.

variant="outline"
Outline

Bordered, no fill. Subtle labels.

variant="ghost"
Ghost

No border or fill. Lowest visual weight.

variant="link"
Link

Underlined on hover. Navigable badges.

With Icons

Place any SVG icon as a child — it is automatically sized and aligned. Use a leading icon for status and a trailing icon for actions.

ActiveDraftErrorVerifiedApproved42

States

Default

Resting

Error

Destructive

Valid

Success

Inactive

Disabled

Invalid

Invalid

Design Guidelines

Do

  • Keep text short. One or two words max — badges are labels, not sentences.
  • Pick variant by semantic weight. Use destructive only for actual errors, default for primary counts or actions.
  • Use icons to reinforce meaning. A status dot or check icon adds instant scannability.

Don't

  • Don't use as a button substitute. If the badge needs a click handler, use a Button with a small size instead.
  • Don't overload with long text. Wrap text breaks the pill shape and looks broken.
  • Don't mix variants for the same concept. Pick one variant per semantic meaning and apply it consistently.

Developer Reference

Accessibility

  • Rendered as <span> by default via useRender — pass render prop to change the element.
  • aria-invalid triggers a destructive ring for validation contexts.
  • Focus ring applies only on focus-visible — keyboard users see it, mouse users do not.
  • SVG children are pointer-events-none shrink-0 to avoid interfering with click targets.

Usage

import { Badge } from "@/components/ui/badge"

// Variants
<Badge>Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="destructive">Destructive</Badge>
<Badge variant="success">Success</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="ghost">Ghost</Badge>
<Badge variant="link">Link</Badge>

// With icon
<Badge><Circle className="size-2 fill-current" />Active</Badge>
<Badge variant="success"><CheckCircle2 className="size-3" />Verified</Badge>
<Badge variant="destructive"><AlertCircle className="size-3" />Error</Badge>

// Disabled
<Badge className="pointer-events-none opacity-50">Inactive</Badge>

// Render as a different element
<Badge render={<a href="/status" />}>View Status</Badge>