Card
A flexible container for grouping related content. Uses a compound component pattern — compose Header, Content, and Footer independently for full layout control.
Compound PatternDark Mode3 VariantsComposable
01
Theme Preview
A profile card rendered with forced light and dark styling — independent of the current app theme.
Light
AJ
Alice Johnson
alice@example.com
AdminActive
Dark
AJ
Alice Johnson
alice@example.com
AdminActive
02
Live Demo
Variant
AJ
Alice Johnson
alice@example.com
AdminActive
trending_up
+12.5%8,249
Monthly visitors
notifications
New comment
Bob left a reply on your post.
03
Code Snippet
src/ui/Card.tsx
import { Card } from "@/ui/Card"; import { Button } from "@/ui/Button"; <Card.Root variant="elevated"> <Card.Header> <Card.Title>Account Settings</Card.Title> <Card.Description> Manage your profile and preferences. </Card.Description> </Card.Header> <Card.Content> <p className="text-sm text-slate-600 dark:text-slate-400"> Your account was last updated 3 days ago. </p> </Card.Content> <Card.Footer> <Button size="sm">Save changes</Button> <Button variant="ghost" size="sm">Cancel</Button> </Card.Footer> </Card.Root>
Flat exports seperti CardHeader, CardContent, dan lainnya tetap didukung untuk migrasi bertahap.
04
Copy-Paste (Single File)
Snippet ini self-contained dan bisa dipindahkan ke project lain tanpa setup alias atau util tambahan.
Card.tsx
import type { HTMLAttributes } from "react"; type ClassValue = string | false | null | undefined; const cn = (...classes: ClassValue[]) => classes.filter(Boolean).join(" "); export type CardVariant = "default" | "elevated" | "flat"; export interface CardProps extends HTMLAttributes<HTMLDivElement> { variant?: CardVariant; } const CARD_VARIANT_CLASSES: Record<CardVariant, string> = { default: "rounded-xl border border-slate-200 bg-white", elevated: "rounded-xl border border-slate-200 bg-white shadow-lg shadow-slate-200/60", flat: "rounded-xl border border-transparent bg-slate-50", }; function CardRoot({ variant = "default", className, children, ...props }: CardProps) { return ( <div className={cn(CARD_VARIANT_CLASSES[variant], className)} {...props}> {children} </div> ); } function CardHeader({ className, children, ...props }: HTMLAttributes<HTMLDivElement>) { return <div className={cn("p-6 pb-4", className)} {...props}>{children}</div>; } function CardTitle({ className, children, ...props }: HTMLAttributes<HTMLHeadingElement>) { return <h3 className={cn("text-base font-bold text-slate-900", className)} {...props}>{children}</h3>; } function CardDescription({ className, children, ...props }: HTMLAttributes<HTMLParagraphElement>) { return <p className={cn("mt-1 text-sm text-slate-500", className)} {...props}>{children}</p>; } function CardContent({ className, children, ...props }: HTMLAttributes<HTMLDivElement>) { return <div className={cn("px-6 pb-4", className)} {...props}>{children}</div>; } function CardFooter({ className, children, ...props }: HTMLAttributes<HTMLDivElement>) { return <div className={cn("px-6 pb-6 flex items-center gap-3", className)} {...props}>{children}</div>; } type CardCompound = typeof CardRoot & { Root: typeof CardRoot; Header: typeof CardHeader; Title: typeof CardTitle; Description: typeof CardDescription; Content: typeof CardContent; Footer: typeof CardFooter; }; export const Card = Object.assign(CardRoot, { Root: CardRoot, Header: CardHeader, Title: CardTitle, Description: CardDescription, Content: CardContent, Footer: CardFooter, }) as CardCompound;
05
Props
All sub-components extend their corresponding HTML element attributes.
| Component | Prop | Type | Default | Description |
|---|---|---|---|---|
Card.Root | variant | "default" | "elevated" | "flat" | "default" | Visual style — border only, shadow, or flat background. |
Card.Root | className | string | — | Additional CSS classes. |
Card.Header | className | string | — | Spacing wrapper for title + description. |
Card.Title | className | string | — | Renders as h3. Bold, dark text. |
Card.Description | className | string | — | Renders as p. Muted, secondary text. |
Card.Content | className | string | — | Main body area with horizontal padding. |
Card.Footer | className | string | — | Action row with flex + gap. Usually holds buttons. |