Badge
A small visual indicator used to highlight status, category, or count. Supports multiple semantic variants and three sizes with automatic dark mode support.
AccessibleDark Mode6 Variants3 Sizes
01
Theme Preview
All six variants across both themes — rendered with forced styling so the comparison is accurate regardless of the current app theme.
Light
DefaultSuccessWarningErrorInfoOutline
sm →Activemd →Reviewlg →Pending
Dark
DefaultSuccessWarningErrorInfoOutline
sm →Activemd →Reviewlg →Pending
02
Live Demo
Size
DefaultSuccessWarningErrorInfoOutline
03
Code Snippet
src/ui/Badge.tsx
import { Badge } from "@/ui/Badge"; // Variants <Badge.Root variant="default">Default</Badge.Root> <Badge.Root variant="success">Active</Badge.Root> <Badge.Root variant="warning">Pending</Badge.Root> <Badge.Root variant="error">Inactive</Badge.Root> <Badge.Root variant="info">Review</Badge.Root> <Badge.Root variant="outline">Draft</Badge.Root> // Sizes <Badge.Root size="sm" variant="success">Small</Badge.Root> <Badge.Root size="md" variant="info">Medium</Badge.Root> <Badge.Root size="lg" variant="default">Large</Badge.Root>
Backward compatible: API lama <Badge /> tetap didukung, canonical style pakai <Badge.Root />.
04
Copy-Paste (Single File)
Badge.tsx
import type { ReactNode } from "react"; type BadgeVariant = "default" | "success" | "warning" | "error" | "info" | "outline"; type BadgeSize = "sm" | "md" | "lg"; interface BadgeProps { variant?: BadgeVariant; size?: BadgeSize; children: ReactNode; className?: string; } const cn = (...classes: Array<string | undefined | false>) => classes.filter(Boolean).join(" "); const VARIANT_CLASSES: Record<BadgeVariant, string> = { default: "bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300", success: "bg-green-100 text-green-700 dark:bg-green-900/40 dark:text-green-400", warning: "bg-amber-100 text-amber-700 dark:bg-amber-900/40 dark:text-amber-400", error: "bg-red-100 text-red-700 dark:bg-red-900/40 dark:text-red-400", info: "bg-blue-100 text-blue-700 dark:bg-blue-900/40 dark:text-blue-400", outline: "border border-slate-300 text-slate-600 dark:border-slate-600 dark:text-slate-400", }; const SIZE_CLASSES: Record<BadgeSize, string> = { sm: "text-[10px] px-2 py-0.5", md: "text-xs px-2.5 py-0.5", lg: "text-sm px-3 py-1", }; function BadgeRoot({ variant = "default", size = "md", children, className }: BadgeProps) { return ( <span className={cn("inline-flex items-center rounded-full font-medium", VARIANT_CLASSES[variant], SIZE_CLASSES[size], className)}> {children} </span> ); } type BadgeCompound = typeof BadgeRoot & { Root: typeof BadgeRoot }; export const Badge = Object.assign(BadgeRoot, { Root: BadgeRoot }) as BadgeCompound;
05
Props
| Prop | Type | Default | Description |
|---|---|---|---|
variant | "default" | "success" | "warning" | "error" | "info" | "outline" | "default" | Controls the color scheme of the badge. |
size | "sm" | "md" | "lg" | "md" | Controls padding and font size. |
children | ReactNode | — | The label content displayed inside the badge. |
className | string | — | Additional CSS classes merged via cn(). |