docs / core / badge
Badge
the status of the thing it sits on. six semantic tones as soft pills, a mono variant for versions and keys, and a pulsing live state. it labels, it never clicks; a clickable pill is Chip.
intensity · recedesrsc · server
provenance
shaped from sisu-pluslayer
core / primitivesintensity
recedes · safe anywhere, including dense surfacescomposition
sits in Card headers, table rows, list items, next to a titlemono for machine values: versions, ids, env namesno onClick, no dismiss. interaction makes it a Chipnot a counter on an icon. that is NotificationBadgea11y
plain text in aspan · the live dot is aria-hiddenjest-axedependencies
class-variance-authoritylive demo · try it out
Passing
customize
tonesemantic color role
labelthe text inside
monouppercase tag for versions, keys
livepulsing green, overrides tone
usage
import { Badge } from "usva/primitives/badge";
<Badge tone="success">Passing</Badge>props
| prop | type | default | notes |
|---|---|---|---|
| tone | "neutral" | "accent" | "accent-alt" | "success" | "warning" | "danger" | "neutral" | semantic color role, rendered as a soft pill. |
| mono | boolean | false | an uppercase monospace tag, for versions, keys and metadata. |
| live | boolean | — | the live green with a pulsing dot. overrides tone. |
get it
npx shadcn add https://usva.build/r/badge.jsonsource · components/ui/badge.tsxexactly what this command copies
import { cva, type VariantProps } from "class-variance-authority";
import type * as React from "react";
import { cn } from "@/lib/utils";
export const badgeVariants = cva(
"inline-flex items-center gap-1.5 rounded-full border px-2.5 py-0.5 text-xs font-medium tabular-nums",
{
variants: {
tone: {
neutral: "border-border bg-surface-2 text-muted",
accent: "border-accent/25 bg-accent/12 text-accent",
"accent-alt": "border-accent-alt/25 bg-accent-alt/12 text-accent-alt",
success: "border-success/25 bg-success/12 text-success",
warning: "border-warning/25 bg-warning/12 text-warning",
danger: "border-danger/25 bg-danger/12 text-danger",
},
mono: {
true: "font-mono text-[0.6875rem] font-semibold uppercase leading-none tracking-wide",
false: "",
},
},
defaultVariants: { tone: "neutral", mono: false },
},
);
export interface BadgeProps
extends React.HTMLAttributes<HTMLSpanElement>,
VariantProps<typeof badgeVariants> {
live?: boolean;
}
export function Badge({
className,
tone,
mono,
live,
children,
...props
}: BadgeProps) {
return (
<span
className={cn(
badgeVariants({ tone, mono }),
live && "border-live/25 bg-live/12 text-live",
className,
)}
{...props}
>
{live ? (
<span
aria-hidden="true"
className="-ml-0.5 h-1.5 w-1.5 rounded-full bg-live animate-live-pulse"
/>
) : null}
{children}
</span>
);
}