Card

A raised surface: border, radius, padding and elevation, and nothing else. The smallest component of the kit, and the one meant to be built on.

API

Props

proptypedefault
as?ElementType"div"the element or component to render
className?stringmerged over the defaults, so it wins
…restprops of astyped against the chosen element

Examples

Usage

A Card is a surface and nothing else: border, radius, padding, background, elevation. What goes inside is your markup, laid out however that content needs.

tsx
<Card>
  <h3>Invoice 0142</h3>
  <p>Issued on 4 August</p>
</Card>
preview

Invoice 0142

Issued on 4 August

Invoice 0143

draft
overdue

As a control

The focus styles ship with the component — the gradient border on focus, an outline on focus-visible — but a div cannot take focus, so they only appear once the card is something that can. When the whole card is clickable, render it as the thing it actually is instead of attaching a click handler to a box.

tsx
<Card as={Link} to="/invoices/142" tabIndex={0}>
  <h3>Invoice 0142</h3>
</Card>
previewclick, or reach them with the keyboard

Button

A card rendered as a link

Media and edge to edge

className is merged over the base classes rather than appended, so an override genuinely replaces what it contradicts: dropping the padding does not need a more specific selector, just p-0. Add overflow-hidden and the content is clipped to the radius.

tsx
<Card className="p-0 overflow-hidden">
  <img src={cover} alt="" />
  <div className="p-5"></div>
</Card>
previewthe fill is clipped to the radius

Cover

p-0 plus overflow-hidden

A tighter padding

tsx
<Card className="p-0 overflow-hidden">
  <img src={cover} alt="" />
</Card>

Details

A surface, not a layout

Card has no header slot, no footer slot and no title prop. The reason is that card layouts differ far more than card surfaces do: a component with fixed slots would be right for one screen and in the way on the next, whereas the surface — the thing that makes it read as a card at all — is the same everywhere.

It also keeps the component honest about what it costs. Everything you see in a card is markup you wrote, so there is never a hidden wrapper to fight when the design changes.

Composing with the decorators

Because it is a single element with a radius, Card is the natural child of the glow decorators: the pseudo-elements inherit its border-radius, so the light follows the rounded corners instead of cutting across them.

tsx
<BorderGlow>
  <Card className="margo-col-span-4"></Card>
</BorderGlow>

On a grid, keep the placement on the Card itself — the decorator clones it rather than wrapping it, so the column utilities belong to the card and nothing is inserted between the grid and its item.

A card that is a control

Both are reachable with the keyboard and announced for what they are — a link that navigates, a button that acts — which a div with an onClick would not be.