Card

A bordered panel that groups one thing on a page.

Overview

A titled block of related content: a record, a status, a list, an empty state.

Status

Do

PixelSlash

Coming soon

Visual review for every pull request.

import { Card, Empty, Pill } from "@hackcove/ui";

<Card title="PixelSlash" status={<Pill tone="amber">Coming soon</Pill>}>
  <Empty>Visual review for every pull request.</Empty>
</Card>
status puts a Pill directly beside the title; actions stays at the far end.
Don't

PixelSlash

Coming soon

Visual review for every pull request.

import { Card, Empty, Pill, SubsectionHeading } from "@hackcove/ui";

<Card>
  <SubsectionHeading>PixelSlash</SubsectionHeading>
  <Pill tone="amber">Coming soon</Pill>
  <Empty>Visual review for every pull request.</Empty>
</Card>
A hand-built title row drifts from every other Card's: use title and status.

Spacing

Do

Open

3

Three things to do.

Done

12

Twelve things finished.

import { Card, Empty, Stack } from "@hackcove/ui";

<Stack>
  <Card title="Open" count={3}>
    <Empty>Three things to do.</Empty>
  </Card>
  <Card title="Done" count={12}>
    <Empty>Twelve things finished.</Empty>
  </Card>
</Stack>
A Stack spaces the Cards; the gap is the one the whole library uses.
Don't

Open

3

Three things to do.

Done

12

Twelve things finished.

import { Card, Empty } from "@hackcove/ui";

<>
  <Card title="Open" count={3}>
    <Empty>Three things to do.</Empty>
  </Card>
  <Card title="Done" count={12}>
    <Empty>Twelve things finished.</Empty>
  </Card>
</>
Cards with nothing between them butt together. Space them with Stack or CardGrid.

Usage

  • Name the Card with title; add a count or a status and they sit beside the title.
  • actions sit at the far end of the header; use bar to put the header in a tinted strip.
  • Space several Cards with a Stack or a CardGrid; never stack them with nothing between.
  • flush is for a table that runs edge to edge, and it needs a bar for its title.
  • footer is a strip across the bottom for the card's own actions or a total; it stays at the foot of a stretched card in a CardGrid.
  • CardGrid takes columns 2, 3 or 4, or columns="auto" with minWidth sm or md to fill by width; align="start" stops cards stretching to the tallest in their row.
  • dashed is the empty state.

Accessibility

  • A Card is a <section> by default and its title names it; as picks another element, e.g. article.
  • id, data-* and aria-* go on the root element.

API

Card

A bordered panel with an optional title, count and status; as picks the element (default section). Three opt-in forms for data views: flush drops the padding and clips the corners, for a table that runs edge to edge; bar puts the title, count and actions in a tinted strip across the top, over the body; dashed is an empty-state shell, a dashed outline with centred muted text. dashed stands alone: it ignores flush and bar; dashed="filled" is the same shell on a surface fill with more padding, for an empty state that must read as a panel. A flush card has no padding for a title, so give it a bar. size="sm" is the dense padding, the same on a ListRow and a FileDrop. tone is the Callout's set, for a data panel that carries a status (a soft fill and border, no shadow); a message is still a Callout, and bar and dashed have no tone. Other props (id, data-*, aria-*) go on the root. The root is relative, so a TextLink stretch inside it covers the card. footer is a tinted strip across the bottom, under a hairline, for the card's own actions or a total; in a CardGrid it stays at the foot of a card that is stretched to the row's height. It suits a panel, not a card that is a link, and dashed has none. href makes the whole card one link: the root is an <a> with a hover border and the focus ring, so it takes no actions and no as. With render it draws the app's own router <Link> (render={(p) => <Link to="/shots/1" {...p} />}). external opens it in a new tab.


actions

Buttons or links at the end of the header: in the strip with bar, else beside the title. A card that is a link has nothing else to click: no actions.

Type
ReactNode

as

A card that is a link is the link: no as.

Type
"article" | "div" | "section"

bar

Put the title, count and actions in a tinted strip above the body, edge to edge.

Type
boolean

count
Type
number

dashed

An empty-state shell: dashed outline, no shadow, no fill, centred muted text. "filled" puts it on a surface fill with more padding.

Type
boolean | "filled"

external

Opens in a new tab: adds target="_blank" and rel="noreferrer".

Type
boolean

flush

No padding and overflow-hidden: the body (a table, a list) fills the card.

Type
boolean

footer

A tinted strip across the bottom of the card, under a hairline, for the card's own actions or a total. It stays at the foot when the card is stretched in a CardGrid. Ignored with dashed. A card that is a link has nothing else to click: no footer.

Type
ReactNode

href
Type
string

render
Type
LinkRender

size

sm is dense padding on the body, heading and bar; a dashed shell keeps its own. Defaults to md.

Type
"sm" | "md"

status

A Pill (or any node) directly beside the title and count, not at the far end like actions. Needs a title.

Type
ReactNode

title
Type
string

tone

A soft fill and border in the Callout's tones, for a data panel with a status. Ignored with bar and dashed.

Type
"positive" | "danger" | "neutral" | "info" | "warn"