gglc-ui

Badge

Pil status setinggi 20. Empat varian shadcn plus tiga nada status yang dibutuhkan layar akuntansi.

Instalasi

npx shadcn@latest add @glc/badge

Penggunaan

import { Badge } from "@/components/ui/badge"

<Badge variant="success">Lunas</Badge>
Lunas

Varian

Empat pertama diwarisi dari shadcn supaya kode hulu langsung jalan. Tiga terakhir adalah tambahan.
DefaultSecondaryOutlineDestructiveLunasJatuh tempoDraf

Badge tidak bisa diklik

Badge sengaja dibuat non-interaktif — ia merender <span>, bukan tombol. Kalau labelnya bisa dipilih atau dihapus, yang kamu butuhkan adalah Chip, dan itu belum diport.

Di dalam baris data

Tempat komponen ini paling sering muncul: kolom status di daftar faktur.
INV-2401PT Sumber Rejeki
Lunas
INV-2402CV Maju Jaya
Jatuh tempo
INV-2403PT Anugerah
Draf

Warna saja tidak boleh jadi satu-satunya pembawa makna. Perhatikan bahwa tiap badge tetap membawa teks — pembaca dengan buta warna mendapat informasi yang sama.

Props

Selain yang di bawah ini, seluruh atribut <span> diteruskan apa adanya.
PropTipeDefaultKeterangan
variant"default" | "secondary" | "outline" | "destructive" | "success" | "warning" | "info""default"Nada visual badge.
asChildbooleanfalseMerender elemen anak alih-alih <span>. Untuk membungkus tautan.

Kode sumber

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 }