Data display
Card
Cards group related content and actions on one surface. Compose them from a header with an optional icon and actions, a body, and a footer; add media on top, turn the whole card into a link, or use selectable cards as large radio and checkbox options. Corners follow the theme radius and the raised variant lifts with a soft shadow.
Usage this month
Ledgerly · Team plan
<Card variant="raised" className="w-full max-w-md"> <CardHeader titleAs="h2" icon={<Gauge strokeWidth={1.75} />} title="Usage this month" description="Ledgerly · Team plan" action={ <Button variant="ghost" size="icon-sm" aria-label="More options"> <Ellipsis strokeWidth={1.75} /> </Button> } /> <CardBody className="flex flex-col gap-4"> <Progress label="API requests" showLabel value={82} valueText="82,140 / 100k" /> <Progress label="Storage" showLabel value={46} valueText="23 / 50 GB" /> <Progress label="Seats" showLabel value={9} max={10} valueText="9 / 10" tone="warning" /> </CardBody> <CardFooter align="between"> <span className="text-[13px] text-muted">Resets on May 1</span> <Button variant="primary" size="sm">Upgrade plan</Button> </CardFooter></Card>Usage
import { Card, CardBody, CardFooter, CardHeader } from "@/components/ui/card"; <Card> <CardHeader title="Usage this month" description="Team plan" /> <CardBody>…</CardBody> <CardFooter>…</CardFooter></Card>Examples
Overview
Usage this month
Ledgerly · Team plan
<Card variant="raised" className="w-full max-w-md"> <CardHeader titleAs="h2" icon={<Gauge strokeWidth={1.75} />} title="Usage this month" description="Ledgerly · Team plan" action={ <Button variant="ghost" size="icon-sm" aria-label="More options"> <Ellipsis strokeWidth={1.75} /> </Button> } /> <CardBody className="flex flex-col gap-4"> <Progress label="API requests" showLabel value={82} valueText="82,140 / 100k" /> <Progress label="Storage" showLabel value={46} valueText="23 / 50 GB" /> <Progress label="Seats" showLabel value={9} max={10} valueText="9 / 10" tone="warning" /> </CardBody> <CardFooter align="between"> <span className="text-[13px] text-muted">Resets on May 1</span> <Button variant="primary" size="sm">Upgrade plan</Button> </CardFooter></Card>Basic
Header and body only: the most common card.
Upgrade to Team
Unlimited projects and shared themes.
Invite up to 10 people, share tokens across projects and get priority support.
<Card className="w-full max-w-sm"> <CardHeader titleAs="h3" title="Upgrade to Team" description="Unlimited projects and shared themes." /> <CardBody> <p className="text-muted">Invite up to 10 people, share tokens across projects and get priority support.</p> </CardBody></Card>Variants
Outline for most content, raised for the one card that should stand out, sunken for secondary panels.
Outline
Default. Hairline border on the surface.
Raised
Soft shadow for cards that lift off the page.
Sunken
Recessed, for secondary panels and wells.
<Card variant="outline">…</Card><Card variant="raised">…</Card><Card variant="sunken">…</Card>Media
CardMedia runs edge to edge on top with a 16:9, 21:9 or square ratio. Images inside are cropped to fit (the preview uses an inline SVG illustration in place of the image).
Quarterly review template
A board-ready deck with charts that read in light and dark.
<Card as="article" className="w-full max-w-sm"> <CardMedia> <img src="/covers/quarterly-review.png" alt="" /> </CardMedia> <CardHeader titleAs="h3" title="Quarterly review template" description="A board-ready deck with charts that read in light and dark." /> <CardBody className="flex flex-wrap gap-1.5"> <Badge>Finance</Badge> <Badge>Charts</Badge> <Badge tone="accent">New</Badge> </CardBody> <CardFooter align="between"> <span className="font-mono text-[13px] text-muted">12 slides</span> <Button variant="secondary" size="sm">Use template</Button> </CardFooter></Card>Interactive
CardLink makes the whole surface clickable while only the title is the link text, so screen readers hear one short link.
<CardLink href="/docs/components/badge" icon={<Palette strokeWidth={1.75} />} title="Badge" description="Status and category labels in six tones and three variants." meta="Data display"/>Selectable
Large radio or checkbox options built on native inputs. Arrow keys move between radios in the same group.
<fieldset className="grid gap-3"> <legend className="mb-3 text-[13px] font-medium">Choose a plan</legend> <SelectableCard name="plan" value="starter" title="Starter" aside="$0" description="One project, community support." /> <SelectableCard name="plan" value="team" title="Team" aside="$24/mo" description="Unlimited projects and shared themes." defaultChecked /> <SelectableCard name="plan" value="business" title="Business" aside="$79/mo" description="SSO, audit log and a dedicated contact." /></fieldset>Props
Card
variant"outline" | "raised" | "sunken"default: "outline"Border only, border with shadow, or recessed fill.as"section" | "article" | "div" | "li"default: "section"Element to render.classNamestringdefault: —Layout classes such as width or grid placement.
CardHeader
titlerequiredReactNodedefault: —Card heading.descriptionReactNodedefault: —One line under the title.iconReactNodedefault: —Icon tile before the title.actionReactNodedefault: —Buttons or a menu on the right.titleAs"h2" | "h3" | "h4" | "p"default: "h2"Heading level, so the card fits the page outline.
CardBody, CardFooter, CardMedia
CardFooter align"start" | "end" | "between"default: "end"How the footer lays out its children.CardMedia aspect"video" | "wide" | "square"default: "video"16:9, 21:9 or 1:1 media area.classNamestringdefault: —Extra classes on the body, footer or media.
CardLink
hrefrequiredstringdefault: —Destination; rendered with next/link.titlerequiredstringdefault: —Link text and heading.descriptionReactNodedefault: —Supporting text.iconReactNodedefault: —Icon tile on top.metaReactNodedefault: —Small line at the bottom.
SelectableCard
type"radio" | "checkbox"default: "radio"Native input type.namerequiredstringdefault: —Group name; radios with the same name are one choice.valuerequiredstringdefault: —Submitted value.titlerequiredReactNodedefault: —Option label.descriptionReactNodedefault: —Extra detail under the title.asideReactNodedefault: —Right-aligned detail such as a price.checked / defaultCheckedbooleandefault: —Controlled or uncontrolled state.onChange(checked: boolean, value: string) => voiddefault: —Called when the input changes.disabledbooleandefault: —Dims the card and blocks interaction.
Accessibility
- Set titleAs so card titles continue the page's heading outline (an h3 under an h2 section, for example).
- CardLink keeps one link per card: the title. A pseudo-element stretches its hit area over the card, and the card shows a focus ring when the link is focused.
- SelectableCard wraps a real radio or checkbox in its label, so clicking anywhere selects it, Space toggles it and arrow keys move within a radio group.
- Group selectable cards in a fieldset with a legend so the question is announced with each option.
- Icon-only actions in the header need an aria-label, like the More options button above.