Skip to content
Design System
Contact

Card

Containers for stats, records and media, from static to interactive.

ComponentsCardPanel

Playground

Cards are built from slots: header (title, description, action), content and footer. Only interactive cards lift on hover, and the whole card is one link whose focus ring wraps the card.

Preview
Customer portal, due Oct 14
SaaSDashboard
Progress64%
MCJBPNUpdated 2h ago

Props

Variant
Size
example.tsxtsx
1import { Card, CardAction, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from "@/components/ui/card"
2
3<Card className="relative transition-[box-shadow,translate] hover:-translate-y-px hover:shadow-lift has-[a[data-card-link]:focus-visible]:ring-2 has-[a[data-card-link]:focus-visible]:ring-ring">
4 <CardHeader>
5 <CardTitle>
6 <Link href="/projects/northwind" data-card-link className="outline-none after:absolute after:inset-0 after:rounded-xl">
7 Northwind onboarding
8 </Link>
9 </CardTitle>
10 <CardDescription>Customer portal, due Oct 14</CardDescription>
11 <CardAction>
12 {/* DropdownMenu trigger, raised above the link with "relative z-10" */}
13 <Button variant="ghost" size="icon-sm" aria-label="Project actions"><Ellipsis /></Button>
14 </CardAction>
15 </CardHeader>
16 <CardContent>{/* tags and progress */}</CardContent>
17 <CardFooter className="justify-between">
18 <AvatarStack names={team} size="xs" />
19 <span className="text-xs text-muted-foreground">Updated 2h ago</span>
20 </CardFooter>
21</Card>

Variants

Pick by job, not by look. Borders separate, shadows only answer the pointer. Radius stays at 12px for every card so nested controls (8px) read as inside.

Card variants
Demo data

Default: static content on the sheet

Quarterly review
Prepared for Acme Corporation
Revenue grew in every region; expansion is now a third of new bookings.

Subtle: secondary groups and callouts

Sync paused
Northwind's CRM connection needs a new token before it can sync again.

Stat: one number with context

Revenue

Up+12%

$2.21M

vs Oct 2024 – Sep 2025

Panel: widgets with a title and an action

Renewals this month

Updated 5 min ago

  • InitechOct 2$4,120
  • HooliOct 9$56,000
  • SoylentOct 21$2,980

Record: a person or company at a glance

PN
Priya Nair
Head of Operations, Globex
Customer
EnterpriseCRMRenewal Q4
Account
Globex, 1,200 seats
Open deal
$32,900
Last contact
Sep 24, 2026

Media: a project with a rendered preview, clickable as a whole

A CRM pipeline with drag-and-drop stages and forecast rollups.
CRMSaaSNext.js

Selectable: radio cards for a few rich options

Engagement type

States

The interactive card at rest and in each state. A selected card uses the brand ring, the same signal as selection everywhere else.

States
  • Globex rollout
    Due Oct 14
    SaaS3 tasks
    Defaultrest
  • Globex rollout
    Due Oct 14
    SaaS3 tasks
    Hovershadow-lift, -translate-y-px
  • Globex rollout
    Due Oct 14
    SaaS3 tasks
    Focushas(a:focus-visible)
  • Loadingaria-busy
  • Globex rollout
    Due Oct 14
    Archived3 tasks
    Disabledaria-disabled
  • Couldn't load project
    The request timed out.
    Errorrole=alert
  • Globex rollout
    Due Oct 14
    SaaS3 tasks
    Successselected

API

PropTypeDefaultDescription
size"default" | "sm""default"Sets --card-spacing to 16px or 12px for padding and gaps between slots.
classNamestring—Variant styling: bg-subtle for subtle cards, hover lift and focus-within ring for interactive ones.
CardHeaderslot—Title and description; becomes a two-column grid when it contains CardAction.
CardActionslot—Top-right action such as a menu. Give it relative z-10 inside an interactive card.
CardContentslot—Body content with horizontal card padding.
CardFooterslot—Muted strip with a top border for meta and secondary actions.
data-card-linkattribute—Marks the stretched title link of an interactive card; the card shows a ring when it has focus.
Panel{ title, description, action, children }—Bordered widget container from common/panel for dashboards and grouped content.

Accessibility

Keyboard

Focus the card link, then its secondary action
Tab
Open the card
Enter
Move between radio cards and select
←or→
Select the focused radio card
Space

Semantics and ARIA

  • Interactive cards use one real <a> on the title stretched over the card with after:inset-0, so the accessible name is the title, not the whole card's text.
  • Secondary actions sit above the stretched link with relative z-10 and stay separate tab stops; never nest a button inside the link.
  • Focus is shown on the card itself with has-[a:focus-visible], so the ring follows the visual target.
  • Radio cards are buttons with role="radio" and aria-checked inside a labelled radiogroup, with one tab stop and arrow-key selection.
  • Media previews are role="img" with a descriptive label; decorative icons are aria-hidden.