gray
radius
Display

Card

A sectioned container. Compound because the order, count and contents of the sections belong to the caller.

Sections

Use the parts you need, in the order you need them. All of them are optional.

style-tokens

Color, spacing, type, shadow, motion

Four consumption formats from one source, so none of them can drift.

<Card.Root>
<Card.Header>
<Card.Title>style-tokens</Card.Title>
<Card.Description>Color, spacing, type, shadow, motion</Card.Description>
</Card.Header>
<Card.Body>
<Text size={4} color="assistive">
Four consumption formats from one source, so none of them can drift.
</Text>
</Card.Body>
<Card.Footer align="end">
<Button variant="ghost" size="s">Docs</Button>
<Button size="s">Install</Button>
</Card.Footer>
</Card.Root>

Elevation

Use elevation to pick a border or a shadow. They are alternatives, not a scale: doing both reads as indecision.

flat

outlined

elevated

{(['flat', 'outlined', 'elevated'] as const).map(elevation => (
<Card.Root key={elevation} elevation={elevation}>
<Card.Body>
<Text size={5} weight="bold">{elevation}</Text>
</Card.Body>
</Card.Root>
))}

Interactive

Use interactive to add hover and focus affordances to a card that is part of a control.

base-react

18 headless primitives

Radix5.6 KBWAI-ARIA
<Card.Root elevation="elevated" interactive>
<Card.Header>
<Card.Title>base-react</Card.Title>
<Card.Description>18 headless primitives</Card.Description>
</Card.Header>
<Card.Body>
{/* Card.Body stacks, so a row of badges brings its own wrapper. */}
<div style={{ display: 'flex', gap: 6, flexWrap: 'wrap' }}>
<Badge size="s" tone="accent">Radix</Badge>
<Badge size="s">5.6 KB</Badge>
<Badge size="s" tone="success">WAI-ARIA</Badge>
</div>
</Card.Body>
</Card.Root>
interactive adds hover and focus affordances. It does not make the card clickable, and a div with an onClick is not reachable by keyboard. Put the handler on a real button or link inside, or make the whole card one.

Parts

Import it as a namespace, and the parts work on either side of the server boundary.

import * as Card from '@minuk-hwang-design-system/components-react/card';
PartWhat it is
Card.RootThe container. Padding lives on the sections, so media can run edge to edge between them.
Card.HeaderTitle and description.
Card.TitleDefaults to h3, since a card is almost never the top of a document outline. A Heading, so it takes every prop of one.
Card.DescriptionAssistive-colored subtitle. A Text, so it takes every prop of one, and leading="reading" opens the line height when it runs long.
Card.BodyThe main content.
Card.FooterActions. align="end" gives the usual cancel/confirm shape.
Card.MediaFull-bleed image, outside the padded sections so it meets the corners.

Props

PropTypeDefaultNotes
elevation'flat' | 'outlined' | 'elevated''outlined'How the card separates itself from the page.
interactivebooleanfalseHover and focus affordances. Does not add behavior.