Card
A surface that groups related content. The reference multi-part component: one tv recipe with slots, shared variants flowing to every part through React Context.
Installation#
Usage#
import {
Card, CardHeader, CardTitle,
CardDescription, CardContent, CardFooter,
} from "@/components/ui/card"
export function Example() {
return (
<Card>
<CardHeader>
<CardTitle>Title</CardTitle>
<CardDescription>Supporting text.</CardDescription>
</CardHeader>
<CardContent>Body content.</CardContent>
<CardFooter>Footer</CardFooter>
</Card>
)
}Playground#
Card is the other shape: two props, and everything else is composition. Turn a Part off and a whole element leaves the snippet, rather than a show-something prop appearing. Drop them all and the card still holds together.
A contour with a hairline shadow, a bare contour, or a filled floating panel.
The padding tier for every part.
A picture inset from the card's edges.
Holds the title, description and action.
A muted line under the title.
A control on the header's trailing edge.
The body.
<Card className="w-full max-w-sm">
<CardHeader>
<CardTitle>Upgrade to Pro</CardTitle>
<CardDescription>Unlock every theme and component.</CardDescription>
</CardHeader>
<CardContent className="text-sm text-muted-foreground">
Billed annually. Cancel anytime from settings.
</CardContent>
<CardFooter className="gap-2">
<Button variant="ghost">Learn more</Button>
<Button>Upgrade</Button>
</CardFooter>
</Card>Anatomy#
Variants#
default and outline sit in the page flow, so they paint no fill: they are contours that take whatever they sit on, the page, a muted band or a dialog. default adds a hairline shadow, outline is the bare border. elevated is the one that floats: it drops the border, leans on shadow, and is the only variant with a fill.
Density#
density flows from the root through context to every part’s padding and the title scale. compact is the Koala default (16px padding & gaps, 1rem title); comfortable is the spacious alternative for marketing layouts. Set it per-card or for a whole subtree with DensityProvider - see Density.
Media#
CardMedia holds a photo, video or screenshot inset from the card’s edges, never bled to them. The inset is 8px on every side, tighter than the copy’s padding, so the picture reads as framed. Its radius is concentric with the card’s: 20px outside, minus 8px of inset, is 12px inside. Badges laid over the picture anchor to the frame, not the card. The frame is aspect-video by default; pass another ratio in className.
Interactive#
When the whole card is the way in (a task on a board, a template in a gallery, a customer in a grid), render it as the link or the button itself: pass asChild around an <a> or a <button>, and interactive to add the pointer, a hover and a focus ring. The hover follows the variant: default lifts and strengthens its edge, outline strengthens its edge with a whisper of lift, elevated rises further. The edge matters on the dark themes, where a shadow alone barely reads. Only the box-shadow moves, and nothing scales under the press. Keep other controls out of an interactive card: a link or button nested in another is invalid, so a card with its own actions stays a plain card with a link in its title.
Action on a narrow card#
A wide action (a period switch, a select) leaves the title a sliver of room on a phone-width card. Pass wrap="narrow" on CardAction and it drops under the title and description once the card header is narrower than 24rem, then returns to the top-right when there is room. It is measured on the header with a container query, so it follows the card, not the viewport: a narrow card on a wide screen wraps too, and a wide card on a tablet does not. It is opt-in because an icon button reads best beside the title at any width. Both cards below hold the same header.