Card
A flexible surface for grouping related content, actions and media.
Card groups related content into a clear visual surface. It can be a simple content container, an interactive card, a link, a horizontal media card, a full-bleed background-media card, a table-like row, or a loading state. All content props accept ReactNode, so buttons, tags, icons, avatars and other components can be composed inside it.
Component model
The regular composition is media → header → body → footer. The generated header contains title, description, titleIcon, badge and actions; supplying header replaces that generated header. layout="row" replaces the regular header/body composition with the columns row, while footer remains available.
Basic card
<Card title="Project overview" description="A short description of the project.">
Review the latest activity and settings for this project.
</Card>The header can also be supplied as custom content. When header is provided, it replaces the generated title, description, badge and actions header.
<Card
header={<div>Custom header content</div>}
footer={<span>Updated just now</span>}
>
Card content goes here.
</Card>Variants and sizes
variant="default"— surface with a control border.variant="outlined"— transparent surface with a border.variant="filled"— tinted control surface.variant="ghost"— no visible border or surface.variant="elevated"— borderless surface with a stronger elevation shadow.variant="flat"— borderless, low-contrast filled surface.size="sm",defaultandlgcontrol spacing and typography.
<Card variant="filled" size="sm" title="Compact card">Compact content.</Card>
<Card variant="outlined" size="lg" title="Large card">More spacious content.</Card>
<Card variant="elevated" title="Elevated card">A card that needs visual emphasis.</Card>
<Card variant="flat" title="Flat card">A quiet card for dense layouts.</Card>Header, actions, badge and footer
title, description, titleIcon, badge and actions create a standard header. footer renders a separated footer row and accepts any React content.
<Card
title="Team members"
description="People with access to this workspace."
badge={<Badge tone="secondary" count={12} />}
titleIcon={<Users aria-hidden="true" size={16} />}
actions={<Button size="sm" variant="outline">Manage</Button>}
footer={<><span>Last synced today</span><Button size="sm">View all</Button></>}
>
Member list content.
</Card>Interactive cards
Use interactive with onClick for an action card, or href for a link card. Interactive cards support keyboard activation and visible focus. Do not place another interactive control over the whole card when using href or onClick; keep secondary actions in a non-conflicting area.
<Card interactive onClick={() => openProject('design')} title="Design system">
Open the project details.
</Card>
<Card href="/projects/design" title="Design system">
Navigate to the project.
</Card>Media and layout
media places an image, illustration or other visual in the card. Vertical cards place media at the top by default; set mediaPosition="bottom" to place it below the content. Horizontal cards place media on the left by default; set mediaPosition="end" to place it on the right.
<Card
orientation="horizontal"
media={<img alt="Workspace preview" src="/workspace-preview.png" />}
title="Workspace preview"
description="A horizontal media layout."
>
Use this layout for previews and featured content.
</Card>
<Card
orientation="horizontal"
mediaPosition="end"
media={<img alt="Workspace preview" src="/workspace-preview.png" />}
title="Media on the right"
>
A horizontal card with the media aligned to the end.
</Card>
<Card
mediaPosition="bottom"
media={<img alt="Workspace preview" src="/workspace-preview.png" />}
title="Media below content"
>
A vertical editorial layout with the media at the bottom.
</Card>
<Card
mediaPosition="background"
backgroundContentPosition="top"
backgroundContentWidth="100%"
media={<img alt="Mountain landscape" src="/mountains.jpg" />}
title="Featured story"
description="Content over a full-bleed image."
>
Use this variant for editorial highlights and featured content.
</Card>mediaPosition="background" is a vertical layout. The media fills the card, a gradient improves text contrast, and the header/body/footer remain above the image. Images use object-fit: cover.
Use backgroundContentPosition to place the text block at the top, bottom, left or right edge of the background image. Use backgroundContentWidth to control its readable measure. It accepts full (or 100%), percentages, pixels, or any valid CSS width such as 420px or min(70%, 520px).
<Card
mediaPosition="background"
backgroundContentPosition="bottom"
backgroundContentWidth="min(72%, 520px)"
media={<img alt="Mountain landscape" src="/mountains.jpg" />}
title="Featured story"
description="A controlled text measure over the image."
>
Keep supporting content near the lower edge while preserving the image around it.
</Card>The position values are interpreted by layout: top and bottom are vertical media placements, start and end are horizontal media placements, and background makes the media fill the card. On narrow screens horizontal cards switch to a stacked flow.
Row cards and columns
Use layout="row" with columns to render one full-width record with table-like columns. Each column accepts a label, arbitrary React content, alignment, and an optional width. Labels are hidden by default; set columnHeaders to show compact column headings.
const columns = [
{ key: 'name', label: 'Project', content: <strong>Atlas CRM</strong> },
{ key: 'owner', label: 'Owner', content: 'Product team' },
{ key: 'status', label: 'Status', content: <Tag tone="success">Active</Tag>, align: 'center' },
{ key: 'updated', label: 'Updated', content: '2 minutes ago', align: 'end' },
];
<Card layout="row" fullWidth columns={columns} columnHeaders columnSizing="equal" />Supported sizing strategies:
<Card layout="row" columns={columns} columnSizing="equal" />
<Card layout="row" columns={columns} columnSizing="content" />
<Card layout="row" columns={columns} columnSizing="between" />
<Card layout="row" columns={columns} columnSizing="fixed" columnWidths={[180, '1fr', 120, 160]} />
<Card layout="row" columns={columns} columnSizing="flex" />equaldistributes all columns evenly;contentsizes columns according to their content;betweenkeeps the first and last columns close to the edges and lets the middle area grow;fixedusescolumnWidthsor individual columnwidthvalues;flexdistributes the available space while allowing long content to shrink.
Set columnHeaders={false} for a compact row without labels. Column content can include buttons, tags, avatars, icons, progress indicators, or any other React component. On narrow screens row columns stack vertically and end/center alignment returns to the start edge.
const actionColumns = [
{ key: 'name', label: 'Workspace', content: <strong>Design system</strong> },
{ key: 'description', label: 'Description', content: 'Shared components and tokens.' },
{ key: 'action', content: <Button size="sm" variant="outline">Open</Button>, align: 'end' },
];
<Card
layout="row"
fullWidth
columns={actionColumns}
columnHeaders
columnSizing="fixed"
columnWidths={[180, '1fr', 110]}
variant="outlined"
/>Loading, disabled and selection states
loadingblocks interaction and displays the token-based loading indicator.disabledprevents interaction and communicates unavailable state.selectedmarks an active card with the primary focus ring.fullWidthstretches the card to its parent width.
loading renders an accessible role="status" loading layer and disables pointer interaction. disabled prevents click handling and communicates unavailable content. selected adds the selected border and focus treatment. For interactive cards, Enter and Space invoke onClick; links use the native anchor behavior. Do not make the entire card interactive and place a conflicting interactive control over the same surface.
Accessibility and semantics
- Use a meaningful
titleor an explicitaria-labelfor standalone cards. - Use
as="section"oras="div"when the surrounding document structure requires it; the default element isarticle. hrefrenders an anchor and takes precedence over custom keyboard activation.titleanddescriptionreceive generated IDs and are connected to the card witharia-labelledbyandaria-describedby.- Images supplied through
mediashould include usefulalttext when they convey information, oralt=""when decorative.
API Reference
| Prop | Type | Default | Description |
|---|---|---|---|
children | ReactNode | — | Main card content. |
aria-label | string | — | Accessible name when the visible title is not sufficient. |
title | ReactNode | — | Generated header title. |
description | ReactNode | — | Supporting header text. |
titleIcon | ReactNode | — | Icon displayed before the title. |
badge | ReactNode | — | Header badge or status content. |
actions | ReactNode | — | Header actions. |
header | ReactNode | — | Fully replaces the generated header. |
footer | ReactNode | — | Footer content separated by a border. |
media | ReactNode | — | Media displayed above or beside the content. |
mediaPosition | top | bottom | start | end | background | top for vertical, start for horizontal | Controls media placement. start/end apply to horizontal cards; top/bottom/background apply to vertical cards. |
backgroundContentPosition | top | bottom | left | right | top | Position of the content block when mediaPosition="background". |
backgroundContentWidth | number | string | 100% | Width of the background-media content block. Numbers are pixels; strings may be full, percentages, or valid CSS widths. |
variant | default | outlined | filled | ghost | elevated | flat | default | Surface treatment. |
size | sm | default | lg | default | Spacing and typography density. |
orientation | vertical | horizontal | vertical | Card layout direction. |
layout | stacked | row | stacked | Uses the regular card composition or a table-like row composition. |
columns | CardColumn[] | — | Row-card columns with optional labels, content, widths, and alignment. |
columnHeaders | boolean | false | Shows compact labels above row-column content. |
columnSizing | equal | content | fixed | between | flex | flex | Column width strategy in row layout. |
columnWidths | (number | string)[] | — | Explicit CSS widths used by fixed sizing. |
interactive | boolean | inferred | Enables click behavior, hover and keyboard focus. |
onClick | (event) => void | — | Action for an interactive card. |
onKeyDown | (event) => void | — | Optional keyboard event handler. It runs before the built-in Enter/Space activation. |
href | string | — | Renders the card as a link. |
selected | boolean | false | Shows selected state. |
loading | boolean | false | Shows a loading overlay and blocks interaction. |
disabled | boolean | false | Disables the card. |
fullWidth | boolean | false | Uses the available width. |
as | article | div | section | article | Semantic element for non-link cards. |
All visual values use the shared theme tokens, including surface, text, border, focus, primary and spacing tokens.
CardColumn has the shape { key?: string; label?: ReactNode; content: ReactNode; width?: number | string; align?: 'start' | 'center' | 'end' }.
Type reference
| Type | Values | Meaning |
|---|---|---|
CardVariant | default, outlined, filled, ghost, elevated, flat | Surface and border treatment. |
CardSize | sm, default, lg | Compact, standard or spacious density. |
CardOrientation | vertical, horizontal | Stacked content or media beside content. |
CardMediaPosition | top, bottom, start, end, background | Media placement within the selected orientation. |
CardBackgroundContentPosition | top, bottom, left, right | Content block edge for background media. |
CardColumnSizing | equal, content, fixed, between, flex | Grid strategy for row columns. |
CardColumnAlign | start, center, end | Horizontal alignment of a row column. |
CardElement | article, div, section | Semantic element used when the card is not a link. |
CardColumn fields
| Field | Type | Default | Description |
|---|---|---|---|
key | string | index | Stable React key for the column. |
label | ReactNode | — | Optional compact heading, rendered only when columnHeaders is true. |
content | ReactNode | required | Column value or composed UI content. |
width | number | string | strategy-dependent | Per-column width; numbers are pixels and strings are CSS grid track values. |
align | start | center | end | start | Column content alignment. |