Skip to content
ExamsLibraryFor agentsConnect your agent
componentsComponents·4/25

Cards design

Don't nest cards. Design card interiors intentionally — whitespace, hover-only actions, subtle icons.

Raw markdown On GitHub

Cards are easy to over-use and easier to over-nest. A well-designed card is a self-contained unit of content with intentional interior structure. Nested cards are usually a sign the design has lost its way.

The no-nesting rule

Bad:  card > card > card (three borders, three shadows, three radii)
Good: card > content with internal hierarchy (one border, one shadow)

If you find yourself reaching for a card-inside-a-card, the inner card is probably:

  • A list item (use a <li> with hover state, not a card).
  • A heading + content block (use typography hierarchy, not a wrapped container).
  • A status indicator (use a badge or chip inline, not a card).

The exception: a single call-out card inside a parent card (e.g., a pinned highlight) can work. Beyond that, you're overusing the pattern.

Designing card interiors

A card is a small layout problem. Its interior deserves the same care as a screen:

  • Whitespace beats borders for separating sections. A 24px gap between header and body reads cleaner than a 1px divider.
  • Hover-only actions for editing, deleting, more options. Show them on :hover (or always on touch).
  • Subtle icons to anchor information types — but don't add an icon to every line. One per card maximum, usually.
  • Variable density inside. A list of recent activity inside the card can be tighter than the card's outer padding.

Example card structure:

<Card>
  <CardHeader>
    <CardTitle>Project Atlas</CardTitle>
    <CardActions show-on-hover>{/* Edit, Archive, Share */}</CardActions>
  </CardHeader>
  <CardMeta>
    <Icon name="folder" /> 12 files · Updated 2h ago
  </CardMeta>
  <CardBody>
    <p>Brief description that fits on 2–3 lines max.</p>
  </CardBody>
  <CardFooter>
    <AvatarStack avatars={collaborators} />
    <Badge>Active</Badge>
  </CardFooter>
</Card>

Card hover states

Most cards in a grid should have a hover state. See hover-states-subtle — the right answer is usually:

  • 1px lift (transform: translateY(-1px)).
  • Slight background-color shift on the card body.
  • Hover-only action buttons fade in.

NOT a 4px lift, NOT a large shadow change. Those are the ai-default-tells.

Cards as the wrong choice

Cards aren't always the right container. Alternatives:

ContentBetter than card
A list of items the user reads top-to-bottomUse a list with hover rows
A single highlighted piece of contentUse typography hierarchy + whitespace
Status that updates frequentlyInline badge or pill
Tabular comparison dataUse a real table (data-is-content)
Long-form contentUse sections with headers, not cards

If your screen is all cards, it probably has no hierarchy. Some content earns a card; most doesn't.

When to apply

  • Grid of equally-weighted items (projects, products, users).
  • Bento layouts on landing pages.
  • Dashboards with discrete widgets.
  • Anywhere the content is self-contained and benefits from a clear boundary.

When NOT to apply

  • Long-form reading.
  • Single-focus screens (each card competes with the focus).
  • Lists where every row is just text + metadata (use rows, not cards).
  • Inside an already-cardified container.

Gotcha

The nested-radius rule from border-radius applies: if a card has border-radius: 12px and contains a media (image, video) that fills the top, the media needs border-radius: 12px 12px 0 0 to match. Most "this card looks off" complaints trace to a mismatched nested radius.

Sources

componentscards