Card
betaA bordered surface that groups related content, with header, title, description, content, and footer parts.
Preview
parts
$24 per month
layouts
Active users
12,480
Billing
- main2 minutes ago
- fix-login1 hour ago
- docsYesterday
2 of 3 passed
Install
1. Add the registry to
components.json, once per app. Without it, the shadcn CLI looks up@txbrendanin a public list that txbrendan/ui does not control.npx shadcn@latest registry add "@txbrendan=https://txbrendan.dev/r/{name}.json"2. Add the theme, once per app. It replaces your color tokens with ones checked for contrast.
npx shadcn@latest add @txbrendan/theme3. Add the component.
npx shadcn@latest add @txbrendan/card
Use it for
- Grouping one topic so it reads as a unit: a plan, a stat, a settings section, a list item with actions.
- Laying out several items of the same kind in a grid.
- Use only the parts you need. A card with just CardContent is fine.
- Density sets the padding and the space between parts, so cards tighten and loosen with the rest of the app.
Avoid it for
- Wrapping the whole page, or putting cards inside cards. Use headings and spacing instead.
- Important messages. Use an Alert, so the message has a tone.
- Making the whole card a click target with onClick on the div. Put a real link or button inside it.
- Rows of a table. Use a table, so screen readers can move by row and column.
Props
- className
Extra classes on any part. Later classes win, so className='px-0' on CardContent lets a table run edge to edge.
string
- Card
The surface. Pads top and bottom with --space-inset and spaces its parts with --space-stack.
ComponentProps<"div">
- CardHeader
Part. Stacks the title and description.
ComponentProps<"div">
- CardTitle
Part. Semibold title. A div, so put an <h2> or <h3> inside when the card needs a heading.
ComponentProps<"div">
- CardDescription
Part. Secondary text in muted-foreground.
ComponentProps<"div">
- CardContent
Part. The body. Pads its sides with --space-inset.
ComponentProps<"div">
- CardFooter
Part. A row for actions or a summary. It wraps on small screens.
ComponentProps<"div">
| Prop | Type | Default | What it does |
|---|---|---|---|
| className | string | - | Extra classes on any part. Later classes win, so className='px-0' on CardContent lets a table run edge to edge. |
| Card | ComponentProps<"div"> | - | The surface. Pads top and bottom with --space-inset and spaces its parts with --space-stack. |
| CardHeader | ComponentProps<"div"> | - | Part. Stacks the title and description. |
| CardTitle | ComponentProps<"div"> | - | Part. Semibold title. A div, so put an <h2> or <h3> inside when the card needs a heading. |
| CardDescription | ComponentProps<"div"> | - | Part. Secondary text in muted-foreground. |
| CardContent | ComponentProps<"div"> | - | Part. The body. Pads its sides with --space-inset. |
| CardFooter | ComponentProps<"div"> | - | Part. A row for actions or a summary. It wraps on small screens. |
Accessibility
- Every part is a plain <div> with no role, so a card adds no noise for screen readers.
- CardTitle is not a heading. Put an <h2> or <h3> inside it at the right level when people should be able to jump between cards.
- Keep links and buttons inside the card. A clickable div is not reachable by keyboard.
- The theme tests hold card-foreground and muted-foreground to 4.5:1 on the card color, in light and dark.
Examples
Header, content, and footer (needs @txbrendan/button)
import { Button } from "@/components/ui/button";
<Card className="max-w-sm">
<CardHeader>
<CardTitle>Pro plan</CardTitle>
<CardDescription>For teams that ship every week.</CardDescription>
</CardHeader>
<CardContent>
<p className="text-2xl font-semibold">$24 per month</p>
</CardContent>
<CardFooter>
<Button tone="brand">Upgrade</Button>
<Button emphasis="ghost">Compare plans</Button>
</CardFooter>
</Card>A stat with only content
<Card>
<CardContent>
<p className="text-sm text-muted-foreground">Active users</p>
<p className="text-3xl font-semibold tabular-nums">12,480</p>
</CardContent>
</Card>A heading inside the title
<Card>
<CardHeader>
<CardTitle>
<h2>Billing</h2>
</CardTitle>
<CardDescription>Your next invoice is on 1 November.</CardDescription>
</CardHeader>
</Card>A list that runs edge to edge
<Card>
<CardHeader>
<CardTitle>Recent deploys</CardTitle>
</CardHeader>
<CardContent className="px-0">
<ul className="divide-y border-y text-sm">
<li className="px-(--space-inset) py-2">main · 2 minutes ago</li>
<li className="px-(--space-inset) py-2">fix-login · 1 hour ago</li>
</ul>
</CardContent>
</Card>