import { Button } from "@/components/ui/button";
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
export function CardDemo() {
return (
<Card className="w-full max-w-sm">
<CardHeader>
<CardTitle>Login to your account</CardTitle>
<CardDescription>
Enter your email below to login to your account
</CardDescription>
<CardAction>
<Button variant="ghost">Sign Up</Button>
</CardAction>
</CardHeader>
<CardContent>
<form>
<div className="flex flex-col gap-6">
<div className="grid gap-2">
<Label htmlFor="email">Email</Label>
<Input
variant="secondary"
id="email"
type="email"
placeholder="m@example.com"
required
/>
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="password">Password</Label>
<a
href="#"
className="ml-auto inline-block text-xs underline-offset-4 hover:underline sm:text-sm"
>
Forgot your password?
</a>
</div>
<Input
variant="secondary"
id="password"
type="password"
required
/>
</div>
</div>
</form>
</CardContent>
<CardFooter className="flex-col gap-2">
<Button type="submit" className="w-full">
Login
</Button>
<Button variant="outline" className="w-full">
Login with Google
</Button>
</CardFooter>
</Card>
);
}
pnpm dlx shadcn@latest add https://herocn.dev/r/card.jsonimport {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"<Card>
<CardHeader>
<CardTitle>Card Title</CardTitle>
<CardDescription>Card Description</CardDescription>
<CardAction>Card Action</CardAction>
</CardHeader>
<CardContent>
<p>Card Content</p>
</CardContent>
<CardFooter>
<p>Card Footer</p>
</CardFooter>
</Card>Use the following composition to build a Card:
Card
├── CardHeader
│ ├── CardTitle
│ ├── CardDescription
│ └── CardAction
├── CardContent
└── CardFooterUse the variant prop to control the visual prominence of the card.
Use for less important content or nested cards
The default card variant for most use cases
Use to draw moderate attention
Use for primary or featured content
import {
Card,
CardContent,
CardDescription,
CardHeader,
CardTitle,
} from "@/components/ui/card";
export function CardVariants() {
return (
<div className="grid grid-cols-1 gap-4 lg:grid-cols-2">
<Card variant="transparent">
<CardHeader>
<CardTitle>Transparent</CardTitle>
<CardDescription>
Minimal prominence with transparent background
</CardDescription>
</CardHeader>
<CardContent>
<p>Use for less important content or nested cards</p>
</CardContent>
</Card>
<Card variant="default">
<CardHeader>
<CardTitle>Default</CardTitle>
<CardDescription>
Standard card appearance (bg-surface)
</CardDescription>
</CardHeader>
<CardContent>
<p>The default card variant for most use cases</p>
</CardContent>
</Card>
<Card variant="secondary">
<CardHeader>
<CardTitle>Secondary</CardTitle>
<CardDescription>
Medium prominence (bg-surface-secondary)
</CardDescription>
</CardHeader>
<CardContent>
<p>Use to draw moderate attention</p>
</CardContent>
</Card>
<Card variant="tertiary">
<CardHeader>
<CardTitle>Tertiary</CardTitle>
<CardDescription>
Higher prominence (bg-surface-tertiary)
</CardDescription>
</CardHeader>
<CardContent>
<p>Use for primary or featured content</p>
</CardContent>
</Card>
</div>
);
}
Use the size="sm" prop to set the size of the card to small. The small size variant uses smaller spacing.
import { ChevronRightIcon } from "lucide-react";
import { Button } from "@/components/ui/button";
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
export function CardSmall() {
const featureName = "Scheduled reports";
return (
<Card size="sm" className="mx-auto w-full max-w-xs">
<CardHeader>
<CardTitle>{featureName}</CardTitle>
<CardDescription>
Weekly snapshots. No more manual exports.
</CardDescription>
</CardHeader>
<CardContent>
<ul className="grid gap-2 py-2 text-sm">
<li className="flex gap-2">
<ChevronRightIcon className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<span>Choose a schedule (daily, or weekly).</span>
</li>
<li className="flex gap-2">
<ChevronRightIcon className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<span>Send to channels or specific teammates.</span>
</li>
<li className="flex gap-2">
<ChevronRightIcon className="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<span>Include charts, tables, and key metrics.</span>
</li>
</ul>
</CardContent>
<CardFooter className="flex-col gap-2">
<Button size="sm" className="w-full">
Set up scheduled reports
</Button>
<Button variant="outline" size="sm" className="w-full">
See what's new
</Button>
</CardFooter>
</Card>
);
}
Add an image before the card header to create a card with an image.
import { Badge } from "@/components/ui/badge";
import { Button } from "@/components/ui/button";
import {
Card,
CardAction,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
export function CardImage() {
return (
<Card className="relative w-full max-w-sm">
<img
src="https://avatar.vercel.sh/shadcn1"
alt="Event cover"
className="relative z-20 aspect-video w-full object-cover"
/>
<CardHeader>
<CardAction>
<Badge>Featured</Badge>
</CardAction>
<CardTitle>Design systems meetup</CardTitle>
<CardDescription>
A practical talk on component APIs, accessibility, and shipping
faster.
</CardDescription>
</CardHeader>
<CardFooter>
<Button className="w-full">View Event</Button>
</CardFooter>
</Card>
);
}
"use client";
import {
type Translations,
useTranslation,
} from "@/components/language-selector";
import { Button } from "@/components/ui/button";
import {
Card,
CardAction,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card";
import { Input } from "@/components/ui/input";
import { Label } from "@/components/ui/label";
const translations: Translations = {
en: {
dir: "ltr",
values: {
title: "Login to your account",
description: "Enter your email below to login to your account",
signUp: "Sign Up",
email: "Email",
emailPlaceholder: "m@example.com",
password: "Password",
forgotPassword: "Forgot your password?",
login: "Login",
loginWithGoogle: "Login with Google",
},
},
ar: {
dir: "rtl",
values: {
title: "تسجيل الدخول إلى حسابك",
description: "أدخل بريدك الإلكتروني أدناه لتسجيل الدخول إلى حسابك",
signUp: "إنشاء حساب",
email: "البريد الإلكتروني",
emailPlaceholder: "m@example.com",
password: "كلمة المرور",
forgotPassword: "نسيت كلمة المرور؟",
login: "تسجيل الدخول",
loginWithGoogle: "تسجيل الدخول باستخدام Google",
},
},
he: {
dir: "rtl",
values: {
title: "התחבר לחשבון שלך",
description: "הזן את האימייל שלך למטה כדי להתחבר לחשבון שלך",
signUp: "הירשם",
email: "אימייל",
emailPlaceholder: "m@example.com",
password: "סיסמה",
forgotPassword: "שכחת את הסיסמה?",
login: "התחבר",
loginWithGoogle: "התחבר עם Google",
},
},
};
export function CardRtl() {
const { dir, language, t } = useTranslation(translations, "ar");
return (
<Card className="w-full max-w-sm" lang={language} dir={dir}>
<CardHeader>
<CardTitle>{t.title}</CardTitle>
<CardDescription>{t.description}</CardDescription>
<CardAction>
<Button variant="ghost">{t.signUp}</Button>
</CardAction>
</CardHeader>
<CardContent>
<form>
<div className="flex flex-col gap-6">
<div className="grid gap-2">
<Label htmlFor="email-rtl">{t.email}</Label>
<Input
variant="secondary"
id="email-rtl"
type="email"
placeholder={t.emailPlaceholder}
required
/>
</div>
<div className="grid gap-2">
<div className="flex items-center">
<Label htmlFor="password-rtl">{t.password}</Label>
<a
href="#"
className="ms-auto inline-block text-xs underline-offset-4 hover:underline md:text-sm"
>
{t.forgotPassword}
</a>
</div>
<Input
variant="secondary"
id="password-rtl"
type="password"
required
/>
</div>
</div>
</form>
</CardContent>
<CardFooter className="flex-col gap-2">
<Button type="submit" className="w-full">
{t.login}
</Button>
<Button variant="outline" className="w-full">
{t.loginWithGoogle}
</Button>
</CardFooter>
</Card>
);
}
| Prop | Type | Default |
|---|---|---|
| variant | "default" | "transparent" | "secondary" | "tertiary" | "default" |
| size | "default" | "sm" | "default" |
| className | string | — |
The CardHeader component is used for a title, description, and optional action.
| Prop | Type | Default |
|---|---|---|
| className | string | — |
The CardTitle component is used for the card title.
| Prop | Type | Default |
|---|---|---|
| className | string | — |
The CardDescription component is used for helper text under the title.
| Prop | Type | Default |
|---|---|---|
| className | string | — |
The CardAction component places content in the top-right of the header (for example, a button or a badge).
| Prop | Type | Default |
|---|---|---|
| className | string | — |
The CardContent component is used for the main card body.
| Prop | Type | Default |
|---|---|---|
| className | string | — |
The CardFooter component is used for actions and secondary content at the bottom of the card.
| Prop | Type | Default |
|---|---|---|
| className | string | — |