gglc-ui

Card

Permukaan berisi konten dengan radius 14, hairline 1px, dan padding 16. Tujuh bagian yang dipasang sesuai kebutuhan.

Instalasi

npx shadcn@latest add @glc/card

Anatomi

import {
  Card,
  CardAction,
  CardContent,
  CardDescription,
  CardFooter,
  CardHeader,
  CardTitle,
} from "@/components/ui/card"

<Card>
  <CardHeader>
    <CardTitle>Judul</CardTitle>
    <CardDescription>Keterangan singkat</CardDescription>
    <CardAction>{/* tombol atau badge */}</CardAction>
  </CardHeader>
  <CardContent>…</CardContent>
  <CardFooter>…</CardFooter>
</Card>

Semua bagian bersifat opsional. CardAction diposisikan di kanan atas header lewat grid, jadi ia harus berada di dalam CardHeader — bukan sesudahnya.

Contoh

Piutang jatuh tempo
3 terbuka · Rp 11.306.000
pending

Angka uang memakai figur tabular supaya kolom nominal sejajar.

Sebagai form

Pola paling sering: header menjelaskan, konten mengumpulkan, footer memutuskan.
Tambah kontak
Data ini dipakai di faktur dan surat jalan.

Bagian

Tidak ada satu pun yang punya props sendiri — semuanya <div> yang meneruskan atributnya, termasuk className.
PropTipeDefaultKeterangan
CarddivPembungkus luar. Radius 14, hairline, latar surface.
CardHeaderdivGrid yang menampung judul, keterangan, dan CardAction di kanan atas.
CardTitledivJudul kartu.
CardDescriptiondivKeterangan sekunder di bawah judul.
CardActiondivSlot kanan atas. Harus di dalam CardHeader agar gridnya bekerja.
CardContentdivBadan kartu.
CardFooterdivBaris aksi di bawah. Biasanya diberi justify-end.

Kode sumber

import * as React from "react"

import { cn } from "@/registry/glc/lib/utils"

/**
 * Card — the file's panel: radius 14, white surface, 1px rgba(9,9,11,.1)
 * hairline, 16px padding, near-flat elevation.
 *
 * The compound shape (Card / CardHeader / CardTitle / …) is shadcn's, so
 * anything written against shadcn's Card drops straight in. The legacy
 * prop-based API (`<Card title description actions footer>`) is gone — see
 * docs/design-system/MIGRATION.md.
 */
function Card({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card"
      className={cn(
        "flex flex-col gap-4 rounded-xl border border-[var(--border-card)] bg-card p-4 text-card-foreground",
        "shadow-[var(--elevation-1)]",
        className
      )}
      {...props}
    />
  )
}

function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-header"
      className={cn(
        "@container/card-header grid auto-rows-min grid-rows-[auto_auto] items-start gap-1",
        "has-data-[slot=card-action]:grid-cols-[1fr_auto]",
        className
      )}
      {...props}
    />
  )
}

function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-title"
      className={cn("text-base leading-6 font-semibold", className)}
      {...props}
    />
  )
}

function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-description"
      className={cn("text-sm leading-5 text-muted-foreground", className)}
      {...props}
    />
  )
}

function CardAction({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-action"
      className={cn("col-start-2 row-span-2 row-start-1 self-start justify-self-end", className)}
      {...props}
    />
  )
}

function CardContent({ className, ...props }: React.ComponentProps<"div">) {
  return <div data-slot="card-content" className={cn(className)} {...props} />
}

function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
  return (
    <div
      data-slot="card-footer"
      className={cn("flex items-center gap-2 [.border-t]:pt-4", className)}
      {...props}
    />
  )
}

export {
  Card,
  CardHeader,
  CardFooter,
  CardTitle,
  CardAction,
  CardDescription,
  CardContent,
}