Permukaan berisi konten dengan radius 14, hairline 1px, dan padding 16. Tujuh bagian yang dipasang sesuai kebutuhan.
npx shadcn@latest add @glc/cardSetiap komponen bergantung pada glc-theme. Lewati langkah ini kalau sudah pernah dijalankan.
npx shadcn@latest add @glc/glc-themeimport * 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,
}Berkas di atas meng-import @/registry/glc/lib/utils. Ubah menjadi lokasi cn di proyekmu — biasanya @/lib/utils. CLI melakukan ini otomatis.
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.
Angka uang memakai figur tabular supaya kolom nominal sejajar.
import { Badge } from "@/registry/glc/ui/badge"
import { Button } from "@/registry/glc/ui/button"
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/registry/glc/ui/card"
export function CardDemo() {
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Piutang jatuh tempo</CardTitle>
<CardDescription>3 terbuka · Rp 11.306.000</CardDescription>
<CardAction>
<Badge variant="warning">pending</Badge>
</CardAction>
</CardHeader>
<CardContent>
<p className="text-sm leading-5 text-muted-foreground">
Angka uang memakai figur tabular supaya kolom nominal sejajar.
</p>
</CardContent>
<CardFooter className="justify-end">
<Button variant="ghost" size="sm">
Batal
</Button>
<Button size="sm">Tagih</Button>
</CardFooter>
</Card>
)
}import { Button } from "@/registry/glc/ui/button"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/registry/glc/ui/card"
import { Input } from "@/registry/glc/ui/input"
import { Label } from "@/registry/glc/ui/label"
import { Textarea } from "@/registry/glc/ui/textarea"
export function CardForm() {
return (
<Card className="w-full max-w-md">
<CardHeader>
<CardTitle>Tambah kontak</CardTitle>
<CardDescription>Data ini dipakai di faktur dan surat jalan.</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<div className="flex flex-col gap-2">
<Label htmlFor="card-form-name">Nama perusahaan</Label>
<Input id="card-form-name" placeholder="PT Contoh Sejahtera" />
</div>
<div className="flex flex-col gap-2">
<Label htmlFor="card-form-note">Catatan</Label>
<Textarea id="card-form-note" placeholder="Syarat pembayaran…" />
</div>
</CardContent>
<CardFooter className="justify-end">
<Button variant="ghost" size="sm">
Batal
</Button>
<Button size="sm">Simpan</Button>
</CardFooter>
</Card>
)
}| Prop | Tipe | Default | Keterangan |
|---|---|---|---|
Card | div | — | Pembungkus luar. Radius 14, hairline, latar surface. |
CardHeader | div | — | Grid yang menampung judul, keterangan, dan CardAction di kanan atas. |
CardTitle | div | — | Judul kartu. |
CardDescription | div | — | Keterangan sekunder di bawah judul. |
CardAction | div | — | Slot kanan atas. Harus di dalam CardHeader agar gridnya bekerja. |
CardContent | div | — | Badan kartu. |
CardFooter | div | — | Baris aksi di bawah. Biasanya diberi justify-end. |
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,
}