Skip to content

Badge

  • The status of an item in a list or table: “Paid”, “Overdue”
  • A category or stage: “Beta”, “New”
  • A count next to a label

Not for something people click or remove — use a Chip or a Button.

Choosing between small labels:

ComponentUse it forFor example
BadgeThe status or category of something, at a glance“Paid”, “Overdue”, “Beta”
ChipTags, filters and metadata, often several in a row“React”, “Remote”, an applied filter
KbdA key on the keyboard, in text or a tooltipPress ⌘ K to search
neutralsuccesswarningerrorinfo
import { Badge } from '@arun-dev/ui';
export default function BadgeTones() {
return (
<>
<Badge>neutral</Badge>
<Badge tone="success">success</Badge>
<Badge tone="warning">warning</Badge>
<Badge tone="error">error</Badge>
<Badge tone="info">info</Badge>
</>
);
}
Status
<Badge tone="neutral">Status</Badge>

The design system ships only generic tones. Anything narrower — an article’s difficulty, an order’s status, a build result — is your vocabulary, and mapping it at the call site keeps it type-checked and keeps the library reusable.

BeginnerIntermediateAdvanced
import { Badge, type BadgeTone } from '@arun-dev/ui';
type Difficulty = 'beginner' | 'intermediate' | 'advanced';
// Domain vocabulary belongs to your app, not the design system. Map it onto a tone
// at the call site, where `satisfies` makes a typo a compile error.
const DIFFICULTY = {
beginner: { label: 'Beginner', tone: 'success' },
intermediate: { label: 'Intermediate', tone: 'warning' },
advanced: { label: 'Advanced', tone: 'error' },
} as const satisfies Record<Difficulty, { label: string; tone: BadgeTone }>;
export default function BadgeDomainMapping() {
return (
<>
{(Object.keys(DIFFICULTY) as Difficulty[]).map((key) => (
<Badge key={key} tone={DIFFICULTY[key].tone}>
{DIFFICULTY[key].label}
</Badge>
))}
</>
);
}
Badge props
PropTypeDefaultDescription
tone'neutral' | 'success' | 'warning' | 'error' | 'info''neutral'Generic status tone, backed by the --color-status-* semantic tokens. Map your own domain vocabulary onto a tone at the call site.
classNamestringConcatenated with the component's own classes, never replacing them.
renderReactElementElement or component to render instead of the default. Props, className, event handlers and ref are merged onto it.
refRef<HTMLElement>Ref to the rendered element. Merged with any ref on the render element.
…restHTMLAttributesAnything else is spread onto the rendered element, so id, aria-*, data-* and event handlers all reach the DOM.
  • Tones are backed by the --color-status-* semantic tokens, so they move with the brand. Override --badge-success-bg to restyle only success badges.
  • neutral adds no tone class, so .badge alone is the neutral appearance.