ComponentsBadge
Badge
Show a short status, label, or count.
On this page
Install component source from the public registry, or use the local workspace package. Follow the setup guide first. The npm package is not published yet.
View registry filesImplemented with React and browser APIs, without an additional behavior or rendering library.
Shared foundation: React, clsx for conditional classes, tailwind-merge for resolving utility-class conflicts. Styles use Tailwind CSS and Dethink CSS variables.
Based on this component’s source and registry composition. Libraries used only in showcase examples are excluded.
Import the component into your page or component file.
import { Badge } from "@dethink/components";
export function Example() {
return <Badge tone="success">Healthy</Badge>;
}Try the examples, then open the code to use them in your app.
Variants and tones
Combine emphasis and semantic tone without hard-coding product colors.
solid
soft
outline
subtle
Show sourceexamples/badge/variants.tsx
"use client";
import {
AlertTriangle,
CheckCircle2,
CircleDot,
Info,
Sparkles,
XCircle,
} from "lucide-react";
import { Badge, type BadgeTone, type BadgeVariant } from "@dethink/components";
const variants: BadgeVariant[] = ["solid", "soft", "outline", "subtle"];
const tones: Array<{
icon: typeof CircleDot;
label: string;
tone: BadgeTone;
}> = [
{ icon: CircleDot, label: "Neutral", tone: "neutral" },
{ icon: Sparkles, label: "Featured", tone: "primary" },
{ icon: CheckCircle2, label: "Healthy", tone: "success" },
{ icon: AlertTriangle, label: "Review", tone: "warning" },
{ icon: XCircle, label: "Failed", tone: "destructive" },
{ icon: Info, label: "AI assisted", tone: "info" },
];
export function BadgeVariants() {
return (
<div className="grid w-full gap-5">
{variants.map((variant) => (
<div key={variant} className="grid gap-2">
<p className="text-muted-foreground text-sm font-medium capitalize">
{variant}
</p>
<div className="flex flex-wrap items-center gap-[var(--dt-space-2)]">
{tones.map(({ icon: Icon, label, tone }) => (
<Badge key={tone} icon={<Icon />} tone={tone} variant={variant}>
{label}
</Badge>
))}
</div>
</div>
))}
</div>
);
}Sizes
Choose xs for dense tables, sm and md for routine metadata, and lg for higher emphasis.
Show sourceexamples/badge/sizes.tsx
"use client";
import { Badge, type BadgeSize } from "@dethink/components";
const sizes: BadgeSize[] = ["xs", "sm", "md", "lg"];
export function BadgeSizes() {
return (
<div className="flex flex-wrap items-center gap-[var(--dt-space-3)]">
{sizes.map((size) => (
<div key={size} className="grid justify-items-center gap-2">
<Badge size={size} tone="primary" variant="soft">
{size.toUpperCase()}
</Badge>
<span className="text-muted-foreground text-xs">{size}</span>
</div>
))}
</div>
);
}Icons
Icons are decorative, so the text label carries the accessible meaning.
Show sourceexamples/badge/icons.tsx
"use client";
import { ArrowRight, CheckCircle2, Clock3, Sparkles } from "lucide-react";
import { Badge } from "@dethink/components";
export function BadgeIcons() {
return (
<div className="flex flex-wrap items-center gap-[var(--dt-space-3)]">
<Badge icon={<CheckCircle2 />} tone="success">
Sync complete
</Badge>
<Badge icon={<Clock3 />} iconPlacement="trailing" tone="warning">
Review pending
</Badge>
<Badge
leadingIcon={<Sparkles />}
trailingIcon={<ArrowRight />}
tone="info"
variant="outline"
>
AI draft ready
</Badge>
</div>
);
}Status list recipe
Badges keep repeated operational states compact and easy to scan.
Show sourceexamples/badge/recipe-status-list.tsx
"use client";
import { AlertTriangle, CheckCircle2, Clock3, XCircle } from "lucide-react";
import {
Badge,
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@dethink/components";
const services = [
{
icon: CheckCircle2,
label: "Healthy",
name: "Billing worker",
tone: "success" as const,
variant: "soft" as const,
},
{
icon: Clock3,
label: "Queued",
name: "Registry smoke",
tone: "info" as const,
variant: "outline" as const,
},
{
icon: AlertTriangle,
label: "Needs review",
name: "Import pipeline",
tone: "warning" as const,
variant: "outline" as const,
},
{
icon: XCircle,
label: "Failed",
name: "Email sender",
tone: "destructive" as const,
variant: "solid" as const,
},
];
export function BadgeStatusList() {
return (
<Card className="w-full max-w-lg">
<CardHeader>
<CardTitle>Service health</CardTitle>
<CardDescription>
Compact badges keep operational state scannable in repeated rows.
</CardDescription>
</CardHeader>
<CardContent className="grid gap-3">
{services.map(({ icon: Icon, label, name, tone, variant }) => (
<div
key={name}
className="flex min-w-0 items-center justify-between gap-[var(--dt-space-4)]"
>
<span className="truncate text-sm font-medium">{name}</span>
<Badge icon={<Icon />} size="xs" tone={tone} variant={variant}>
{label}
</Badge>
</div>
))}
</CardContent>
</Card>
);
}BadgeProps extends span attributes for routine metadata and status labels.
| Prop | What it does | Default |
|---|---|---|
variant"solid" | "soft" | "outline" | "subtle" | Visual weight of the badge. | "soft" |
tone"neutral" | "primary" | "success" | "warning" | "destructive" | "info" | Semantic color tone resolved through design tokens. | "neutral" |
size"xs" | "sm" | "md" | "lg" | Badge height, padding, gap, and text size. | "md" |
iconReactNode | Decorative icon placed according to iconPlacement unless explicit leading or trailing icons are set. | Not set |
iconPlacement"leading" | "trailing" | Position for the icon prop. | "leading" |
leadingIconReactNode | Decorative icon rendered before the badge label. | Not set |
trailingIconReactNode | Decorative icon rendered after the badge label. | Not set |
childrenReactNode | Visible badge label. Keep it short enough for dense rows. | Not set |