Badge
A small inline pill for status, category, or counts. Six tones, an optional leading dot that can pulse for "live" states, and an icon slot for when a dot isn't expressive enough.
defaultlivewarningerrorinfoaccent
Customize
Tone
success
Dot
static
Installation
npx shadcn@latest add https://craftbits.dev/r/badge.jsonUsage
import { Badge } from "@craft-bits/core";
<Badge tone="success" dot="static">live</Badge>A pulsing dot is one prop away:
<Badge tone="accent" dot="pulse">streaming</Badge>Understanding the component
- Tone-driven palette.
toneselects six semantic color combos (default,success,warning,error,info,accent). The background is a muted surface so the badge sits softly on any page; the foreground borrows the tone color so the eye snaps to the status. - Dot variants.
dot="none"(default) renders just the label.dot="static"adds a solid 6px dot before the text.dot="pulse"layers a ring on top that scales outward and fades — the classic "live" indicator. - Pulse via CSS, not JS. The
@keyframes cb-badge-pulserule is injected once into<head>when the first pulsing badge mounts. It's wrapped in@media (prefers-reduced-motion: no-preference)so reduced-motion users see a static dot automatically — no JS branch. - Icon slot. Passing
iconreplaces the dot. The icon inherits the badge's text color viacurrentColor, so alucide-reacticon picks up the tone without extra props. - Sized for inline use.
align-middlekeeps the badge optically centered against surrounding text;whitespace-nowrapprevents long status labels from wrapping mid-flow.
Props
| Prop | Type | Default | Description |
|---|---|---|---|
tone | 'default' | 'success' | 'warning' | 'error' | 'info' | 'accent' | 'default' | Semantic color tone. |
dot | 'none' | 'static' | 'pulse' | 'none' | Leading status dot. pulse adds a halo that respects prefers-reduced-motion. |
icon | ReactNode | — | Optional leading icon. Renders in place of the dot. |
children | ReactNode | required | Label text. |
className | string | — | Merged onto the rendered <span>. |
Accessibility
- The badge renders as a single
<span>whose visible label is announced as-is by screen readers. Wrap it in an element withrole="status"oraria-live="polite"when the value changes dynamically and you want announcements. - The dot and any icon are marked
aria-hidden="true"so assistive tech reads only the label. - The pulse animation is automatically disabled when
prefers-reduced-motion: reduceis set — the rule is scoped under@media (prefers-reduced-motion: no-preference). Reduced-motion users see a static dot identical todot="static".
Credits
- Extracted from:
craftingattention(app/src/components/ui/Badge.tsx).