Card
Surface that groups related content: 8px radius, border, soft shadow in light mode.
When to use
- Dashboard widgets, settings sections and summary panels.
- Kanban and grid items — `variant="interactive"` when the card opens something.
Consider an alternative
- Lists of work items — use rows, not a card per item.
- Inside another card — flatten with a separator instead.
- Dialog bodies — the dialog is already a surface.
Import
import { Card } from '@revido-llc/kit';Props
Props documented by the Kit. Refer to the TypeScript types for the complete interface, including inherited props.
Related exports
CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter
Examples
Anatomy
Header (title, description, action), content and footer. The parts own the padding: 24px outer edge, 16px between header and body — don't add `py-*` to the Card.
<Card className="w-full max-w-sm">
<CardHeader>
<CardTitle>Open proposals</CardTitle>
<CardDescription>Sent in the last 30 days</CardDescription>
<CardAction>
<MenuTrigger>
<Button variant="ghost" size="icon-sm" aria-label="More">
<MoreHorizontal />
</Button>
<Menu placement="bottom end" aria-label="Proposal actions">
<MenuItem id="edit" leading={{ kind: "icon", icon: <Pencil /> }}>Edit</MenuItem>
<MenuItem id="duplicate" leading={{ kind: "icon", icon: <Copy /> }}>Duplicate</MenuItem>
<MenuSeparator />
<MenuItem id="delete" leading={{ kind: "icon", icon: <Trash2 /> }} tone="danger">Delete</MenuItem>
</Menu>
</MenuTrigger>
</CardAction>
</CardHeader>
<CardContent className="flex flex-col gap-3">
<div className="flex items-baseline gap-2">
<span className="text-2xl font-semibold tabular-nums">€ 62.000</span>
<Badge variant="soft" tone="success">+12% vs last month</Badge>
</div>
<div className="flex items-center justify-between">
<AvatarGroup max={3} size="sm">
<Avatar name="Ana Silva" />
<Avatar name="Bram de Vries" />
<Avatar name="Chloé Martin" />
<Avatar name="Daan Jansen" />
</AvatarGroup>
<span className="text-xs text-foreground-tertiary">4 awaiting a reply</span>
</div>
</CardContent>
<CardFooter>
<Button size="sm" variant="ghost">Dismiss</Button>
<Button size="sm">Review</Button>
</CardFooter>
</Card>Interactive
Hover strengthens the border; put the link or button inside.
<Card variant="interactive">
<CardHeader className="pb-6">…</CardHeader>
</Card>Settings section
Header, form body and a footer action row. Footer actions sit 24px below the body and 24px above the card edge; with `border-t` the footer gets 24px above the actions too.
<Card>
<CardHeader>
<CardTitle>Defaults</CardTitle>
<CardDescription>Applied to new projects.</CardDescription>
</CardHeader>
<CardContent className="flex flex-col gap-4">
<TextField label="Default hourly rate (€)" defaultValue="95" />
<TextField label="Proposal validity (days)" defaultValue="30" />
</CardContent>
<CardFooter>
<Button variant="ghost">Cancel</Button>
<Button>Save changes</Button>
</CardFooter>
</Card>Content only
CardContent has no top padding by design (header owns the top edge). Without CardHeader, add `pt-6` on the first CardContent — or prefer CardHeader + CardTitle for titled sections.
<Card>
<CardContent className="pt-6">…</CardContent>
</Card>Literal anatomy
Static component anatomy; bind events in the consuming app.
<Card><CardHeader><CardTitle>Draft</CardTitle><CardAction><Button variant="ghost">Edit</Button></CardAction></CardHeader><CardContent>Ready for review.</CardContent></Card>Stored brand preview
Only the preview banner uses the stored business fill and contrasting text. Ordinary panels retain semantic surfaces.
<Card accent={{ color: moduleColor, width: 3 }}>
<CardHeader colors={{ background: brandFill, foreground: contrastingText }}>
<CardTitle>Proposal</CardTitle>
</CardHeader>
<CardContent>Proposal details</CardContent>
</Card>