Skip to content

Foundation

Card

Beta

A bordered, rounded container for composing header/content/footer regions on top of a themed Surface. Card owns the outer chrome (border colour, radius, optional dividers) — it does not dictate typography or layout inside its slots.

Default

Default

header, content, and footer are opaque ReactNode slots — Card doesn't dictate their internal typography or layout. In real usage, pad the content yourself (see Basic usage below) — plain strings are used here only because this live example can't render nested JSX props.

Plumbing jobLeaking tap in the kitchenPosted 2 days ago
<Card
header="Plumbing job"
content="Leaking tap in the kitchen"
footer="Posted 2 days ago"
/>

Dividers

topDivider renders a horizontal Divider between header and content; bottomDivider renders one between content and footer. Both default to false.

With dividers

topDivider and bottomDivider separate the three regions.

Plumbing jobLeaking tap in the kitchenPosted 2 days ago
<Card
header="Plumbing job"
content="Leaking tap in the kitchen"
footer="Posted 2 days ago"
topDivider
bottomDivider
/>

Border

Two token-driven border colours are available. The default is strong.

Border colours

default (--color-border-default) and strong (--color-border-strong, the default).

border="default"
border="strong"
<div className="flex flex-col gap-6">
<Card border="default" content='border="default"' />
<Card border="strong" content='border="strong"' />
</div>

Radius

Three token-driven corner radii are available. The default is lg (12px).

Radius ramp

sm (4px), md (8px), and lg (12px, default).

radius="sm"
radius="md"
radius="lg"
<div className="flex flex-col gap-6">
<Card radius="sm" content='radius="sm"' />
<Card radius="md" content='radius="md"' />
<Card radius="lg" content='radius="lg"' />
</div>

Surface tone

tone and emphasis pass straight through to the underlying Surface, so any tone-aware component placed in a slot (e.g. Text) automatically picks up the right ink colour.

Neutral vs. inverse

tone passes through to the underlying Surface.

tone="neutral"
tone="inverse"
<div className="flex gap-4">
<Card tone="neutral" content='tone="neutral"' />
<Card tone="inverse" content='tone="inverse"' />
</div>

Card on an inverse Surface

Matching Card's tone to its containing Surface keeps the chrome consistent with the canvas it sits on.

Card tone matches its Surface canvas
<Surface tone="inverse" className="rounded-lg p-6">
<Card tone="inverse" content="Card tone matches its Surface canvas" />
</Surface>

When to use

Use Card to group a header, content, and/or footer region inside a single bordered, rounded container — e.g. a job summary, a review, or a product tile. Card composes Surface (background/tone) and Divider (section separators) rather than reimplementing either.

Slots

header, content, and footer are all optional, opaque ReactNode slots. Card renders whichever are provided and stays out of the way of their internal typography or layout — style the contents yourself with Text, Heading, or any other component.

Dividers

Add topDivider/bottomDivider when the header or footer needs a visible separation from the main content, e.g. a card with a title bar and a metadata footer. Leave them off for a single, undivided block of content.

Border and radius

PropTypical use
borderstrong (default) for most cards; default for a subtler outline
radiuslg (default) for most cards; sm/md when nesting inside another card or a tighter layout

When not to use

  • A full-bleed section with no border/radius: use Surface directly.
  • A specific, pre-composed card pattern (contact card, review card, product marketing card, etc.): those are dedicated components layered on top of Card — use them instead of rebuilding their layout from scratch.

Props

Standard platform props also pass through to the underlying Surface (HTMLAttributes<HTMLDivElement> on web, ViewProps on native) — e.g. id/aria-* on web, nativeID/testID on native. className/style stay blocked. Note that the DOM’s own content?: string (RDFa) attribute is omitted from the web passthrough so it doesn’t collide with the content slot below.

Prop Type Default Description
border 'default' | 'strong' 'strong' Token-driven border colour. Maps to --color-border-{default,strong} (web) / colorBorder{Default,Strong} (native).
radius 'sm' | 'md' | 'lg' 'lg' Token-driven corner radius. Maps to --border-radius-{sm,md,lg} (web) / borderRadius{Sm,Md,Lg} (native).
tone 'neutral' | 'inverse' | 'brand-primary' | 'brand-secondary' 'neutral' Passthrough to the underlying Surface.
emphasis 'default' | 'strong' 'default' Passthrough to the underlying Surface.
header ReactNode - Top slot. Omitted entirely when absent.
content ReactNode - Middle slot. Omitted entirely when absent.
footer ReactNode - Bottom slot. Omitted entirely when absent.
topDivider boolean false Renders a horizontal Divider between header and content.
bottomDivider boolean false Renders a horizontal Divider between content and footer.
data-testid string - Web only. Forwarded to the underlying Surface.

Import

Web

import { Card } from '@checkatrade/components-web';

Native

import { Card } from '@checkatrade/components-native';

Basic usage

<Card
  header={<div className="px-6 py-4">Plumbing job</div>}
  content={<div className="px-6 py-4">Leaking tap in the kitchen</div>}
  footer={<div className="px-6 py-4">Posted 2 days ago</div>}
  topDivider
  bottomDivider
/>

Card doesn’t add padding to its slots — pad the content yourself (as shown above), the way you would for any container with opaque children. Text doesn’t accept a className prop (its visual API is locked down), so wrap it in a padded div/span rather than trying to pad Text directly.

Platform status

Platform / AreaStatus
Design (Figma) Beta
Web (React) Beta
Native (React Native) Beta
iOS (Swift) Planned
Android (Kotlin) Planned
Accessibility audit Planned

Accessibility

Card has no accessibility behaviour of its own — accessibility is driven entirely by whatever is passed into header/content/footer, plus the standard platform attributes (aria-*/data-testid on web, nativeID/testID on native) that pass through to the underlying Surface.

Known gaps

  • No media slot (image at the top of the card) yet — deferred until a real use case appears.

No releases yet.