A white block on the tinted page. It groups things by fill alone — no border, no shadow.
Light
Static card · spacing.card inset
4-week streak
Train once this week to keep it
Last session Tuesday
Flush card · padded={false}, rows draw to the edge
Dark
Static card · spacing.card inset
4-week streak
Train once this week to keep it
Last session Tuesday
Flush card · padded={false}, rows draw to the edge
Source:
Card.tsx. The surface law behind it is in elevation.
When to use it
- To hold one thing that belongs together: a streak, a "for you" suggestion, an index of rows.
- With
padded={false}when rows or media draw to the card's edge. - With
onPresswhen the whole card is one destination.
Not on a white surface — a card only exists against surface.page. Not around inputs: an
input's fill is already surface.card, so an input in a card is white on white. Not stacked
two-deep above an index, or the screen turns into a dashboard.
Anatomy
| Part | Token |
|---|---|
| Fill | surface.card |
| Ground it must sit on | surface.page |
| Corner | radius.card 16, and it clips its children to it |
| Inset | spacing.card 16 (padded, the default) or 0 |
| Pressable floor | touchTarget 44 |
States
Light
Pressable · default
Coaching
2 clips awaiting review
Pressed
Coaching
2 clips awaiting review
Focus
Coaching
2 clips awaiting review
Dark
Pressable · default
Coaching
2 clips awaiting review
Pressed
Coaching
2 clips awaiting review
Focus
Coaching
2 clips awaiting review
- Static (no
onPress): a plain view. No role, no focus stop, no press state. - Pressed:
opacity.pressed0.85. - Focus: a 2px
border.focusring. - Disabled, loading, error: a card has none of its own. A card whose content is loading shows that content's skeleton; one whose content failed shows the error inside it.
On web the ring is the browser's. A pressable Card does not draw its own focus ring; on RN-web it relies on
the browser's default focus outline. Input, SearchField and SelectTrigger draw the 2px
border.focus themselves; the specimen shows the ring this component owes.
Content
- One subject per card. If it needs a second heading, it is two cards or one list.
- An eyebrow may label it; the card's own title is
rowTitle, nottitle. - Nothing inside a pressable card is separately tappable. If it needs a second target, use a
Row with
trailingInteractive.
Accessibility
- A pressable card defaults to role
button. Give it anaccessibilityLabelthat reads the card the way a person would summarise it, because its children are fused into one stop. - Fill is the only separation, so the card has to sit on
surface.pagefor the edge to exist at all. On a white ground it disappears for everyone.
Do and don't
Adult karate
Tuesday · 6:30 pm
Do
A white card on the tinted page. Fill alone separates it.
Adult karate
Tuesday · 6:30 pm
Don’t
A tinted card on a white ground, or a shadow to rescue it. Both are invisible.
Code
import { Card, Text } from '../../components/ui';
<Card onPress={openCoaching} accessibilityLabel="Coaching. 2 clips awaiting review" testID="train-coaching">
<Text variant="rowTitle">Coaching</Text>
<Text variant="caption" tone="secondary">2 clips awaiting review</Text>
</Card>