Card
Displays a card with header, content, and footer — one spacing variable drives every section gap and part inset.
- Status
- Since
0.1.0- Accessibility pattern
- plain container, no implicit role
Last updated
Install
Configure registry credentials first using the Quickstart. Before copying this item or any transitive registry dependency, verify the signed manifest and save the exact bytes for Card before installation. Retain the digest printed by this command.
pnpm exec vegastack-design verify cardInstall with the pinned shadcn CLI. Bare shadcn does not verify VegaStack signature or integrity.
pnpm dlx shadcn@4.21.0 add @vegastack/cardRun the exact offline --post-write command printed by the preflight, using its saved item path and independently retained --expected-integrity digest. Use the saved preflight for every transitive registry dependency too; stop on any mismatch before using the components.
Usage
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>;Anatomy
Examples
Composition
CardHeader holds the title, the description and the action; CardContent holds the body;
CardFooter holds what closes the card. CardAction places itself in the top corner of the header
grid, so it is written inside CardHeader rather than floated over the card.
Size
Use size="sm" to set the card to the small size, which uses smaller spacing throughout.
Variant
variant="outline" keeps the border and drops the fill, so the card reads as a bordered group on
the page rather than a raised panel — a record's side-panel cards (Record Aside)
and dashboard cards. default is the filled card.
Spacing
In addition to the size prop, the --card-spacing CSS variable controls the gap between sections
and the inset of every card part. Set it on the root and every part follows.
Use negative margins with -mx-(--card-spacing) to take content edge to edge while keeping it
aligned with the card inset. When that content sits above a footer, add -mb-(--card-spacing) to
CardContent to remove the section gap.
Image
Add an image before the card header to create a card with an image. The root drops its top padding and rounds the first and last image for you.
RTL
The card is written in logical properties throughout, so a right-to-left document mirrors the header grid, the action corner and the part insets without any extra work.
As a heading
CardTitle renders a div by default. Pass render to make it the real heading at the level the
page needs; the classes and the data-slot stay the same.
<CardTitle render={<h3 />}>Usage this month</CardTitle>API Reference
Card
| Prop | Type | Default | Description |
|---|---|---|---|
size | "default" | "sm" | — | |
variant | "default" | "outline" | — |
CardHeader
CardHeader adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
CardTitle
CardTitle adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
CardDescription
CardDescription adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
CardAction
CardAction adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
CardContent
CardContent adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
CardFooter
CardFooter adds no props of its own — it accepts everything the underlying element or Base UI primitive accepts (className, ref, ARIA attributes, event handlers).
Accessibility
- Every part renders a plain
divwith no implicit role, so a card adds nothing to the accessibility tree on its own. Give it the landmark or heading it deserves — passrender={<h2 />}toCardTitle, or wrap the card in asectionwith an accessible name. CardTitleis styled, not semantic, until it is givenrender(API-22). A page of cards still needs a real heading level so the document outline reads correctly.- Keep the reading order the visual order:
CardActionsits in the top corner but is written insideCardHeader, after the title and description, which is where a keyboard reaches it. - An image placed before the header is decorative in these examples and takes an empty
alt. Give it a real description when it carries information the copy does not.
| Contract | States tested |
|---|---|
| Behaviour | default |
| Accessibility | native-or-base-ui-semantics, browser-accessibility-test |
| Visual | default |
Do / Don't
Deviations
Upstream's file plus packages/ui/upstream/patches/card.patch. Every hunk:
- BRD-1 — the card draws a real 1px
border border-borderinstead of upstream'sring-1 ring-foreground/10box-shadow outline. A border survives forced colours and matches Elevation. It sits inside the box, sooverflow-hiddenclips a full-bleed image at the border's inner edge and the corners stay concentric. - API-22 —
CardTitlerenders through Base UI'suseRender, so it takesrenderand the heading level is set on the part. The defaultdiv, thedata-slotand the classes are upstream's. - API-16 —
"use client"is added:useRendercallsReact.useRefinternally, so the module needs the client boundary to import in a Server Component. - DOC-2 —
cnis imported from@vegastack/design.
Nothing else. The --card-spacing mechanism, the seven parts and every other class are upstream's,
byte for byte; the remaining diff is the repository formatter reflowing the file.