Card
betav0.1.0A composed surface built on Paper: header, title, subtitle, content, footer and a metadata strip, every part optional and combinable. What varies in structure composes; what varies in appearance is a root prop. Card declares no surface, typography or spacing of its own — the root is a Paper and every text goes through Text. Give it href or onClick and the whole card becomes one control whose accessible name is its title, while the buttons, chips and checkboxes inside it stay separate, reachable controls.
Variants
The defined card types
One per variant of the Figma set CardDefault (7233:50454). Copy the snippet as it stands — every control already carries size="sm", no icon button is primary, and no button is highlight.
<Card>
<CardHeader
icon={<Thumbnail><Icon name="server" size={24} /></Thumbnail>}
action={<Icon name="users" size={24} aria-label="Shared" />}
>
<CardTitle>Card title</CardTitle>
<CardSubtitle>Card subtitle or category</CardSubtitle>
</CardHeader>
<CardContent>Lorem ipsum dolor sit amet…</CardContent>
<CardFooter>
<Chip label="Active" severity="low" />
<div className="flex items-center gap-2">
<Button size="sm" priority="tertiary">Learn More</Button>
<Button size="sm" priority="secondary">Deploy</Button>
</div>
</CardFooter>
</Card>- Known as:
- -
- Used Malware
- Malware Name, Malware Name, Malware very long name
- Targeted Countries:
- Countries Name, Countries Name longue
- Targeted Sectors:
- Sector Name, Sector Name longue
<Card>
<CardHeader action={<Icon name="flag" size={24} aria-label="Country" />}>
<CardTitle>Card title</CardTitle>
<CardSubtitle>Card subtitle or category</CardSubtitle>
</CardHeader>
<CardContent>Lorem ipsum dolor sit amet…</CardContent>
{/* the field block is host-composed in v1 */}
<CardFooter>
<div className="flex items-center gap-2">
<Chip label="windows" />
<Chip label="critical" severity="critical" />
</div>
<IconButton icon={<Icon name="star" />} aria-label="Bookmark" size="sm" priority="tertiary" />
</CardFooter>
</Card><Card>
<CardHeader
icon={<Thumbnail><Icon name="server" size={24} /></Thumbnail>}
action={<Badge dot tone="success" accessibleText="Online" />}
>
<CardTitle>Card title</CardTitle>
<CardSubtitle>Card subtitle or category</CardSubtitle>
</CardHeader>
<CardContent clamp={1}>Lorem ipsum dolor sit amet…</CardContent>
<CardFooter>
<Chip label="Active" severity="low" />
<IconButton icon={<Icon name="ellipsis-vertical" />} aria-label="Actions" size="sm" priority="tertiary" />
</CardFooter>
<CardMetaBar>
<span>Message: 0</span>
<span>Last Seen: Aug 7, 2026, 11:34</span>
</CardMetaBar>
</Card>12 480
<Card gap={16}>
<div className="flex h-6 items-center gap-2">
<Text as="span" variant="content-compact">Entities</Text>
<Chip label="+ 23%" severity="low" />
</div>
<div className="flex items-center justify-between gap-4">
<Text as="p" variant="title-2xl">12 480</Text>
<Thumbnail><Icon name="server" size={24} /></Thumbnail>
</div>
</Card><Card padding={0} gap={0}>
<img src={coverUrl} alt="" className="h-[150px] w-full shrink-0 object-cover" />
<div className="flex min-w-0 flex-col gap-6 px-6 py-4">
<CardHeader icon={<Thumbnail><Icon name="newspaper" size={24} /></Thumbnail>}>
<CardTitle>Card title</CardTitle>
<CardSubtitle>Card subtitle or category</CardSubtitle>
</CardHeader>
<CardContent clamp={1}>Lorem ipsum dolor sit amet…</CardContent>
<CardFooter>
<Chip label="Active" severity="low" />
<div className="flex items-center gap-2">
<IconButton icon={<Icon name="thumbs-up" />} aria-label="Like" size="sm" priority="tertiary" />
</div>
</CardFooter>
</div>
</Card>Composing your own card
The parts are optional and combinable, in any order. When no defined type fits, compose header, content and footer yourself.
<Card>
<CardHeader
icon={<Thumbnail><Icon name="bug" size={24} /></Thumbnail>}
action={<Checkbox aria-label="Select this card" />}
>
<CardTitle>Card title</CardTitle>
<CardSubtitle>Card subtitle or category</CardSubtitle>
</CardHeader>
<CardFooter>
<div className="flex items-center gap-2">
<Chip label="windows" />
<Chip label="critical" severity="critical" />
</div>
</CardFooter>
</Card><Card href={`/threats/${id}`}>
<CardHeader
icon={<Thumbnail><Icon name="bug" size={24} /></Thumbnail>}
action={<IconButton icon={<Icon name="bookmark" />} aria-label="Bookmark" size="sm" priority="tertiary" />}
>
<CardTitle>APT29</CardTitle>
<CardSubtitle>Intrusion set</CardSubtitle>
</CardHeader>
<CardFooter>
<Chip label="apt" onClick={filter} />
<Button size="sm" priority="secondary">Deploy</Button>
</CardFooter>
</Card><Card padding={16}>
<CardHeader icon={<Thumbnail><Icon name="shield" size={24} /></Thumbnail>}>
<CardTitle>Card title</CardTitle>
</CardHeader>
</Card>A card takes the width it is given
No intrinsic width, no height. The same card sits in a narrow column and in a full-width row; the title and subtitle truncate at the track edge and keep the full text on the tooltip.
Examples
<Card href="/threats/apt29">
<CardHeader action={<IconButton icon={<Icon name="bookmark" />} aria-label="Bookmark" size="sm" priority="tertiary" />}>
<CardTitle>APT29</CardTitle>
<CardSubtitle>Intrusion set</CardSubtitle>
</CardHeader>
<CardContent clamp={3}>Attributed to a state-sponsored group.</CardContent>
<CardFooter>
<Chip label="apt" />
<Button size="sm" priority="secondary">Deploy</Button>
</CardFooter>
</Card><Card padding={16}>
<CardHeader icon={<Paper padding={8} className="flex size-12 items-center justify-center"><Icon name="newspaper" size={24} /></Paper>}>
<CardTitle>Weekly report</CardTitle>
</CardHeader>
</Card><Card selected>
<CardHeader action={<Checkbox checked aria-label="Select" />}>
<CardTitle>Credential dumping</CardTitle>
</CardHeader>
</Card>Props
| Prop | Type |
|---|---|
elevation | 0 | 1 | 2 | 3 — passed through to Paper. Default 1. |
padding | 0 | 8 | 16 | 24 | 32 (px) — passed through to Paper. Default 24. |
gap | 0 | 8 | 16 | 24 | 32 (px) — the gutter between the parts. Default 24, the node's value everywhere except the statistic composition, which draws 16. |
href | string — makes the whole card navigable. The anchor is rendered by CardTitle and stretched over the surface, so the card is one control named by its title. Mutually exclusive with onClick. |
onClick | handler — same mechanism as href, as a button. Mutually exclusive with href. |
selected | boolean — repaints the surface with the hover couple. The selection itself is carried by a Checkbox in the header action slot; the surface reinforces it. |
disabled | boolean — only meaningful on an interactive card. Renders the title as text. |
CardHeader.icon | ReactNode — leading slot. The node draws a 48x48 Paper holding a 24px Icon. |
CardHeader.action | ReactNode — trailing slot: an Icon, an IconButton, a Checkbox. Free slot. |
CardTitle.as | h2 | h3 | h4 | h5 | h6 | div — no heading level is applied by default. |
CardTitle.endAdornment | ReactNode — trailing content on the title line. |
CardSubtitle.endAdornment | ReactNode — trailing content on the subtitle line. |
CardContent.clamp | number — clamp the text to N lines. Defaults to 3, the node's 56px box (3 lines of 14px/1.5, half-leading trimmed). Pass 0 to let the content grow. |
Accessibility
The card resolves to ONE control: the anchor or button lives on the title and is stretched over the surface by a pseudo-element, so the accessible name is the title rather than the concatenation of the card's text, the markup nests no interactive element, and every inner control keeps its own tab stop. The root generates the title id. Hover is driven by :has() on that control, so pointing at an inner control drops the card highlight. The focus ring is the library's standard pattern and is a declared divergence from the node, which draws no focus state (Card.figma.json). Disabled follows WCAG 1.4.3 note 1: the surface does not change and only the text ramp moves, which is why no disabled pair is declared above. Selected paints the same couple as hover by design — the Checkbox carries the selection.