- Accordion
- Alert
- Alert Dialog
- Aspect Ratio
- Attachment
- Avatar
- Badge
- Breadcrumb
- Bubble
- Button
- Button Group
- Card
- Checkbox
- Collapsible
- Combobox
- Context Menu
- Date Picker (Lite)
- Dialog
- Direction
- Drawer
- Dropdown Menu
- Empty
- Field
- Hover Card
- Input
- Input Group
- Input OTP (Lite)
- Item
- Kbd
- Label
- Marker
- Menubar
- Message
- Native Select
- Navigation Menu
- Pagination
- Popover
- Progress
- Radio Group
- Scroll Area
- Select
- Separator
- Sheet
- Sidebar
- Skeleton
- Slider
- Spinner
- Switch
- Table
- Tabs
- Textarea
- Toast
- Toggle
- Toggle Group
- Tooltip
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 default function CardDemo() {
return (
<Card class="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="link">Sign Up</Button>
</CardAction>
</CardHeader>
<CardContent>
<form>
<div class="flex flex-col gap-6">
<div class="grid gap-2">
<Label for="email">Email</Label>
<Input
id="email"
type="email"
placeholder="m@example.com"
required
/>
</div>
<div class="grid gap-2">
<div class="flex items-center">
<Label for="password">Password</Label>
<a
href="#"
class="ml-auto inline-block text-sm underline-offset-4 hover:underline"
>
Forgot your password?
</a>
</div>
<Input id="password" type="password" required />
</div>
</div>
</form>
</CardContent>
<CardFooter class="flex-col gap-2">
<Button type="submit" class="w-full">
Login
</Button>
<Button variant="outline" class="w-full">
Login with Google
</Button>
</CardFooter>
</Card>
)
}Installation
pnpm dlx shadcnui-hono-jsx@latest add cardnpx shadcnui-hono-jsx@latest add cardyarn dlx shadcnui-hono-jsx@latest add cardbunx shadcnui-hono-jsx@latest add cardUsage
import {
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>Composition
Use the following composition to build a Card:
Card
├── CardHeader
│ ├── CardTitle
│ ├── CardDescription
│ └── CardAction
├── CardContent
└── CardFooterSize
Use the size="sm" prop to set the size of the card to small. The small size variant uses smaller spacing.
- Choose a schedule (daily, or weekly).
- Send to channels or specific teammates.
- Include charts, tables, and key metrics.
import { ChevronRightIcon } from "@/components/icons"
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" class="mx-auto w-full max-w-xs">
<CardHeader>
<CardTitle>{featureName}</CardTitle>
<CardDescription>
Weekly snapshots. No more manual exports.
</CardDescription>
</CardHeader>
<CardContent>
<ul class="grid gap-2 py-2 text-sm">
<li class="flex gap-2">
<ChevronRightIcon class="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<span>Choose a schedule (daily, or weekly).</span>
</li>
<li class="flex gap-2">
<ChevronRightIcon class="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<span>Send to channels or specific teammates.</span>
</li>
<li class="flex gap-2">
<ChevronRightIcon class="mt-0.5 size-4 shrink-0 text-muted-foreground" />
<span>Include charts, tables, and key metrics.</span>
</li>
</ul>
</CardContent>
<CardFooter class="flex-col gap-2">
<Button size="sm" class="w-full">
Set up scheduled reports
</Button>
<Button variant="outline" size="sm" class="w-full">
See what's new
</Button>
</CardFooter>
</Card>
)
}Spacing
In addition to the size prop, you can use the --card-spacing CSS variable to control the spacing between sections and the inset of card parts.
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"
import { ToggleGroup, ToggleGroupItem } from "@/components/ui/toggle-group"
const spacingOptions = [
{
className: "[--card-spacing:--spacing(4)]",
label: "16px",
value: "4",
},
{
className: "[--card-spacing:--spacing(5)]",
label: "20px",
value: "5",
},
{
className: "[--card-spacing:--spacing(6)]",
label: "24px",
value: "6",
},
{
className: "[--card-spacing:--spacing(8)]",
label: "32px",
value: "8",
},
]
export function CardSpacing() {
return (
<div class="group/card-spacing mx-auto grid w-full max-w-sm gap-4">
<ToggleGroup
defaultValue={["4"]}
variant="outline"
size="sm"
class="justify-center"
>
{spacingOptions.map((option) => (
<ToggleGroupItem key={option.value} value={option.value}>
{option.label}
</ToggleGroupItem>
))}
</ToggleGroup>
{/* The pressed item's spacing, following the native radios with :has(). */}
<Card class="group-has-[[value='5']:checked]/card-spacing:[--card-spacing:--spacing(5)] group-has-[[value='6']:checked]/card-spacing:[--card-spacing:--spacing(6)] group-has-[[value='8']:checked]/card-spacing:[--card-spacing:--spacing(8)]">
<CardHeader>
<CardTitle>Login to your account</CardTitle>
<CardDescription>
Enter your email below to login to your account
</CardDescription>
<CardAction>
<Button variant="link">Sign Up</Button>
</CardAction>
</CardHeader>
<CardContent>
<form>
<div class="flex flex-col gap-6">
<div class="grid gap-2">
<Label for="email-spacing">Email</Label>
<Input
id="email-spacing"
type="email"
placeholder="m@example.com"
required
/>
</div>
<div class="grid gap-2">
<div class="flex items-center">
<Label for="password-spacing">Password</Label>
<a
href="#"
class="ml-auto inline-block text-sm underline-offset-4 hover:underline"
>
Forgot your password?
</a>
</div>
<Input id="password-spacing" type="password" required />
</div>
</div>
</form>
</CardContent>
<CardFooter class="flex-col gap-2">
<Button type="submit" class="w-full">
Login
</Button>
<Button variant="outline" class="w-full">
Login with Google
</Button>
</CardFooter>
</Card>
</div>
)
}Use negative margins with -mx-(--card-spacing) to make content go edge to edge while keeping it aligned with the card inset. When the edge-to-edge content sits above a footer, use -mb-(--card-spacing) on CardContent to remove the section gap.
These terms govern your use of the workspace, including access to shared documents, project files, and collaboration tools.
You are responsible for the content you upload and for ensuring that your team has the appropriate permissions to view or edit it.
We may update features or limits as the service evolves. When those changes materially affect your workflow, we will notify your workspace administrators.
By continuing, you agree to keep your account credentials secure and to follow your organization's acceptable use policies.
import { Button } from "@/components/ui/button"
import {
Card,
CardContent,
CardDescription,
CardFooter,
CardHeader,
CardTitle,
} from "@/components/ui/card"
export function CardEdgeToEdge() {
return (
<Card class="mx-auto w-full max-w-sm">
<CardHeader>
<CardTitle>Terms of Service</CardTitle>
<CardDescription>
Review the terms before accepting the agreement.
</CardDescription>
</CardHeader>
<CardContent class="-mb-(--card-spacing)">
<div class="-mx-(--card-spacing) max-h-48 space-y-4 overflow-y-scroll border-t bg-muted/50 px-(--card-spacing) py-4 text-sm leading-relaxed">
<p>
These terms govern your use of the workspace, including access to
shared documents, project files, and collaboration tools.
</p>
<p>
You are responsible for the content you upload and for ensuring that
your team has the appropriate permissions to view or edit it.
</p>
<p>
We may update features or limits as the service evolves. When those
changes materially affect your workflow, we will notify your
workspace administrators.
</p>
<p>
By continuing, you agree to keep your account credentials secure and
to follow your organization's acceptable use policies.
</p>
</div>
</CardContent>
<CardFooter class="justify-end gap-2">
<Button variant="outline">Decline</Button>
<Button>Accept</Button>
</CardFooter>
</Card>
)
}Image
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 class="relative mx-auto w-full max-w-sm pt-0">
<div class="absolute inset-0 z-30 aspect-video bg-black/35" />
<img
src="https://avatar.vercel.sh/shadcn1"
alt="Event cover"
class="relative z-20 aspect-video w-full object-cover brightness-60 grayscale dark:brightness-40"
/>
<CardHeader>
<CardAction>
<Badge variant="secondary">Featured</Badge>
</CardAction>
<CardTitle>Design systems meetup</CardTitle>
<CardDescription>
A practical talk on component APIs, accessibility, and shipping
faster.
</CardDescription>
</CardHeader>
<CardFooter>
<Button class="w-full">View Event</Button>
</CardFooter>
</Card>
)
}RTL
To enable RTL support in shadcn/ui, see the RTL configuration guide.
// This example sets dir and uses useTranslation because this site is not RTL.
// In an RTL app you won't need them; see the RTL guide.
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, t } = useTranslation(translations, "ar")
return (
<Card class="w-full max-w-sm" dir={dir}>
<CardHeader>
<CardTitle>{t.title}</CardTitle>
<CardDescription>{t.description}</CardDescription>
<CardAction>
<Button variant="link">{t.signUp}</Button>
</CardAction>
</CardHeader>
<CardContent>
<form>
<div class="flex flex-col gap-6">
<div class="grid gap-2">
<Label for="email-rtl">{t.email}</Label>
<Input
id="email-rtl"
type="email"
placeholder={t.emailPlaceholder}
required
/>
</div>
<div class="grid gap-2">
<div class="flex items-center">
<Label for="password-rtl">{t.password}</Label>
<a
href="#"
class="ms-auto inline-block text-sm underline-offset-4 hover:underline"
>
{t.forgotPassword}
</a>
</div>
<Input id="password-rtl" type="password" required />
</div>
</div>
</form>
</CardContent>
<CardFooter class="flex-col gap-2">
<Button type="submit" class="w-full">
{t.login}
</Button>
<Button variant="outline" class="w-full">
{t.loginWithGoogle}
</Button>
</CardFooter>
</Card>
)
}Notes
- Accepts
classinstead ofclassName. - Upstream documentation: shadcn/ui Card. See also Differences from shadcn/ui.
API Reference
Card
The Card component is the root container for card content.
| Prop | Type | Default |
|---|---|---|
size | "default" | "sm" | "default" |
className | string | - |
CardHeader
The CardHeader component is used for a title, description, and optional action.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardTitle
The CardTitle component is used for the card title.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardDescription
The CardDescription component is used for helper text under the title.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardAction
The CardAction component places content in the top-right of the header (for example, a button or a badge).
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardContent
The CardContent component is used for the main card body.
| Prop | Type | Default |
|---|---|---|
className | string | - |
CardFooter
The CardFooter component is used for actions and secondary content at the bottom of the card.
| Prop | Type | Default |
|---|---|---|
className | string | - |