skip to content
menu
components · card

card

A card groups content about one thing in a framed panel, often under a short title. It is the usual container for grouped content.

storage-01
412 GB used of 1 TB. Last checked 2 minutes ago.

when to use

  • To group content about one thing under a short title: a volume's details, a run's summary, a section of settings.
  • To give a table or a list a frame and a title, with a flush card.
  • As a sunken card, for a panel inside another panel.

when to use something else

  • For something people open or launch. A card isn't clickable. An entry on the home page is a tile; an action is a button.
  • For padding or a background without a title. Use a box.
  • For a message, such as a save that worked, a list that could not load, or something that needs attention. Use a banner.
  • For content that has to interrupt people. Use a modal.

anatomy

  1. Frame. A square panel with a thin border.
  2. Header (when there is a title or an aside). A row across the top, with a thin line below it: the title on the left, the aside on the right, and a gap between them.
  3. Title. A short name for what's inside, in monospace and lowercase. It can shrink, and it wraps onto a second line when it is long.
  4. Aside (optional). The card's own actions, or a count, at the right end of the header. It never shrinks.
  5. Body. The content, with space around it. A flush card leaves that space out.
  6. Footer (optional). A row across the bottom, with a thin line above it.

variants and states

With no title, aside or footer, a card is a framed panel with space inside.

db-0 is healthy. Last checkpoint 12s ago.

A title goes above the body, and a footer below it.

api-7f9c
Queue drained. 4 packages published to storage-01.

The aside holds the card's own actions and a count. When the header gets crowded, the title gives way to it.

volumes
12
1.2 TB used across 12 volumes.

A sunken card sits on a darker shade of the canvas. Use it for a panel inside another panel, so the two read apart.

storage-01
412 GB used of 1 TB
last backup
Tonight at 02:00, kept 14 days.

A flush card leaves out the space around its body, so a table meets the frame. The card's frame is then the only one: the table inside draws none of its own.

volumes
volumeused (gb)
storage-01412
storage-0296

When people should be able to find a card by its heading, give it a real heading as its title, and name the card as a region by that heading (see accessibility).

backups

Backups run every night at 02:00 and are kept for 14 days.

behaviour

  • A card has no click, no look under the pointer, and no selected or disabled state. It takes no focus; the controls inside it do.
  • The header comes first. So tab reaches the actions in the header before the body, and the footer last.

The full keyboard map is on the card's React page.

accessibility

  • A card has no role and no name of its own.
  • An action in the aside that is only an icon needs a name. Use an icon button, which requires one.
  • The title is lowercase only in its look. A screen reader reads it as you wrote it.

Today: the title isn't a heading, and it doesn't name the card. When people should find the card by its heading, make its title a real heading; it can keep the title's look. Then make the card a region named by that heading, as the last example above does.

content

  • The title. A short noun phrase in lowercase that names what's inside: “volumes”, “last backup”, “storage-01”. No verbs, and no full stop.
  • The body. The reader's text, written in sentence case.
  • The aside. One or two actions, or a count. Anything more goes into an action menu.
  • The footer. A summary, such as “3 of 12 shown”, or the card's closing actions.

do and don't

do
volumes
12
1.2 TB used across 12 volumes.
A short noun as the title, and a count in the aside.
don't
here are all of the volumes in this project
12
1.2 TB used across 12 volumes.
A sentence as the title. It wraps, pushes the aside, and says what the body should say.
do
storage-01
last backup
Tonight at 02:00, kept 14 days.
A panel inside a card is sunken, so the two surfaces read apart.
don't
storage-01
last backup
Tonight at 02:00, kept 14 days.
A standard card inside a standard card: the same surface, two frames, and no depth.
  • Box: padding and a background, without a header.
  • Table: the usual body of a flush card.
  • Tile: an entry on the home page that people click.
  • Heading: the titles of pages and sections, above the cards.

specs

part spec
Frame A --surface fill (--bg-2 when sunken), a 1px --border frame, border-radius: 0; text in --fg-2.
Header Shown when header or headerAside is set. Padding 12px 16px and a 1px --border rule below; the title on the left and the aside on the right, at least 12px apart.
Title header. JetBrains Mono 600, 13px, letter-spacing 0.01em, --fg, lowercased with text-transform. It can shrink (min-width: 0) and wraps when long.
Aside headerAside. Right-aligned and never shrinks; its items 8px apart.
Body The card's children. Padding 16px; flush removes it.
Footer footer. Padding 12px 16px and a 1px --border rule above.
setting in code what it does
Sunken sunken The card on --bg-2 instead of --surface, for a panel inside another surface.
Flush flush No body padding, so a table meets the frame.
A named section A heading element as header, and role="region" with aria-labelledby on the card The title is a real heading that keeps the title's look (margin: 0, font: inherit), and the card is a region named by it.
  • Order: the header, then the body, then the footer, so tab reaches the aside's controls first.
  • Role and name: none of its own. The title renders in a div, not a heading.