Skip to main content

Card

Moleculebeta@macaw-ds/ui · since 0.1.0

A bordered surface that groups related content: a KPI, a form section, a record summary. Not a page, not a modal.

When to use

To group one idea on a dashboard or record page: a KPI, a form section, a summary of a related object, a short table. The border does the work; elevation is optional.

When not to use

  • As the page. A page is the canvas; cards sit on it. Do not wrap a whole page in one card.
  • Nested. A card inside a card is a sign the inner one wants to be a section with a heading instead.
  • As a modal or popover. Those need focus management and a backdrop (later components).

Anatomy

<Card>
  <Card.Header>
    <div>
      <Card.Title>Gross volume</Card.Title>
      <Card.Description>Last 30 days</Card.Description>
    </div>
    <Badge tone="success" dot>
      Live
    </Badge>
  </Card.Header>
  <Card.Body>…</Card.Body>
  <Card.Footer>
    <Button variant="ghost">Cancel</Button>
    <Button>Save</Button>
  </Card.Footer>
</Card>

Card.Header and friends are also exported as CardHeader, CardTitle, CardDescription, CardBody and CardFooter. Use the named exports from React Server Components; the dotted form is only reachable from client components.

padding is set once on the Card and every section follows it. padding="none" lets a table or image run edge to edge.

KPI card recipe

Label in label-sm secondary, value in numeric-lg, delta in caption with a status tone. Three to four across in a grid with gap-4.

Accessibility

  • Card.Title is an h3 by default. Set as so heading levels stay in order on the page.
  • An interactive card is an anchor or a button rendered through asChild. It gets the shared focus ring and must not contain other interactive elements.
  • Static cards have no role and are not focusable; screen readers read them as regular content.

Do and don't

Do

  • Use padding="none" and put a table in Card.Body so rows run edge to edge.

  • Use Card.Description for a one-line summary under the title.

Don't

  • Do not nest cards.

  • Do not use elevation to signal importance; use position and heading level.

Rules

Hard rules an agent must follow. The reviewer agent and the lint config check the ones that can be checked.

  1. Use the sections (Header, Body, Footer) rather than custom padding; the Card owns its spacing.
  2. Card.Title sets the heading level with `as` to fit the page outline.
  3. Interactive cards use asChild with an anchor or a button and contain no other interactive elements.
  4. One primary action per card footer at most.
  5. From a React Server Component, import the named parts (CardHeader, CardBody, CardFooter); the dotted form (Card.Header) only works inside client components.