Pil status setinggi 20. Empat varian shadcn plus tiga nada status yang dibutuhkan layar akuntansi.
npx shadcn@latest add @glc/badgenpm install @radix-ui/react-slot class-variance-authoritySetiap komponen bergantung pada glc-theme. Lewati langkah ini kalau sudah pernah dijalankan.
npx shadcn@latest add @glc/glc-themeimport * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/registry/glc/lib/utils"
/**
* Badge — height 20, pill radius, 2/8 padding, Inter Medium 12/16.
*
* Carries shadcn's four variants (default · secondary · outline · destructive)
* so upstream code drops in, plus the three status tones the accounting UI
* needs (success · warning · info). Non-interactive by design — reach for Chip
* when the thing is removable or selectable.
*/
const badgeVariants = cva(
[
"inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden",
"rounded-[var(--radius-badge)] border border-transparent px-2 py-0.5",
"text-xs leading-4 font-medium whitespace-nowrap",
"[&>svg]:pointer-events-none [&>svg]:size-3",
],
{
variants: {
variant: {
default: "bg-primary text-primary-foreground",
secondary: "bg-secondary text-secondary-foreground",
outline: "border-border bg-card text-foreground",
destructive: "bg-[var(--danger-tint)] text-[var(--text-error)]",
success: "bg-[var(--ok-tint)] text-[var(--text-success)]",
warning: "bg-[var(--warn-tint)] text-[var(--text-warning)]",
info: "bg-[var(--accent-tint)] text-[var(--text-info)]",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Badge({
className,
variant,
asChild = false,
...props
}: React.ComponentProps<"span"> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : "span"
return (
<Comp
data-slot="badge"
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
)
}
export { Badge, badgeVariants }Berkas di atas meng-import @/registry/glc/lib/utils. Ubah menjadi lokasi cn di proyekmu — biasanya @/lib/utils. CLI melakukan ini otomatis.
import { Badge } from "@/components/ui/badge"
<Badge variant="success">Lunas</Badge>import { Badge } from "@/registry/glc/ui/badge"
export function BadgeDemo() {
return <Badge>Lunas</Badge>
}import { Badge } from "@/registry/glc/ui/badge"
export function BadgeVariants() {
return (
<div className="flex flex-wrap items-center gap-2">
{/* shadcn's four — upstream code drops in unchanged. */}
<Badge variant="default">Default</Badge>
<Badge variant="secondary">Secondary</Badge>
<Badge variant="outline">Outline</Badge>
<Badge variant="destructive">Destructive</Badge>
{/* The three status tones the accounting UI needs. */}
<Badge variant="success">Lunas</Badge>
<Badge variant="warning">Jatuh tempo</Badge>
<Badge variant="info">Draf</Badge>
</div>
)
}Badge tidak bisa diklik
<span>, bukan tombol. Kalau labelnya bisa dipilih atau dihapus, yang kamu butuhkan adalah Chip, dan itu belum diport.import { Badge } from "@/registry/glc/ui/badge"
import { Separator } from "@/registry/glc/ui/separator"
const ROWS = [
{ id: "INV-2401", contact: "PT Sumber Rejeki", status: "success", label: "Lunas" },
{ id: "INV-2402", contact: "CV Maju Jaya", status: "warning", label: "Jatuh tempo" },
{ id: "INV-2403", contact: "PT Anugerah", status: "info", label: "Draf" },
] as const
export function BadgeInRow() {
return (
<div className="w-full max-w-md">
{ROWS.map((row, i) => (
<div key={row.id}>
{i > 0 ? <Separator /> : null}
<div className="flex items-center justify-between gap-4 py-3">
<div className="flex flex-col">
<span className="text-sm leading-5 font-medium">{row.id}</span>
<span className="text-sm leading-5 text-muted-foreground">
{row.contact}
</span>
</div>
<Badge variant={row.status}>{row.label}</Badge>
</div>
</div>
))}
</div>
)
}Warna saja tidak boleh jadi satu-satunya pembawa makna. Perhatikan bahwa tiap badge tetap membawa teks — pembaca dengan buta warna mendapat informasi yang sama.
| Prop | Tipe | Default | Keterangan |
|---|---|---|---|
variant | "default" | "secondary" | "outline" | "destructive" | "success" | "warning" | "info" | "default" | Nada visual badge. |
asChild | boolean | false | Merender elemen anak alih-alih <span>. Untuk membungkus tautan. |
import * as React from "react"
import { Slot } from "@radix-ui/react-slot"
import { cva, type VariantProps } from "class-variance-authority"
import { cn } from "@/registry/glc/lib/utils"
/**
* Badge — height 20, pill radius, 2/8 padding, Inter Medium 12/16.
*
* Carries shadcn's four variants (default · secondary · outline · destructive)
* so upstream code drops in, plus the three status tones the accounting UI
* needs (success · warning · info). Non-interactive by design — reach for Chip
* when the thing is removable or selectable.
*/
const badgeVariants = cva(
[
"inline-flex h-5 w-fit shrink-0 items-center justify-center gap-1 overflow-hidden",
"rounded-[var(--radius-badge)] border border-transparent px-2 py-0.5",
"text-xs leading-4 font-medium whitespace-nowrap",
"[&>svg]:pointer-events-none [&>svg]:size-3",
],
{
variants: {
variant: {
default: "bg-primary text-primary-foreground",
secondary: "bg-secondary text-secondary-foreground",
outline: "border-border bg-card text-foreground",
destructive: "bg-[var(--danger-tint)] text-[var(--text-error)]",
success: "bg-[var(--ok-tint)] text-[var(--text-success)]",
warning: "bg-[var(--warn-tint)] text-[var(--text-warning)]",
info: "bg-[var(--accent-tint)] text-[var(--text-info)]",
},
},
defaultVariants: {
variant: "default",
},
}
)
function Badge({
className,
variant,
asChild = false,
...props
}: React.ComponentProps<"span"> &
VariantProps<typeof badgeVariants> & { asChild?: boolean }) {
const Comp = asChild ? Slot : "span"
return (
<Comp
data-slot="badge"
className={cn(badgeVariants({ variant }), className)}
{...props}
/>
)
}
export { Badge, badgeVariants }