Live example
Header, body and footer · body="inset" size="lg"
Profile
This is how others will see you
Last saved 2 minutes ago
Simple card: content straight inside, padded evenly
Delete this post?
It is deleted permanently. This cannot be undone.
Variants
default
A bordered box on canvas, for primary content.
muted
A quieter tint for secondary panels.
soft
The faintest tint, for light grouping.
outline
Just the border, over whatever is behind it.
filled
A tint with no edge, for inline surfaces.
Sizes
xs
Compact, for dense lists.
sm
Tight, for small widgets.
md
The default.
lg
Roomy, for forms.
Body treatments
body="seamless"
Notifications
Choose what you hear about
Saved automatically
body="inset"
Notifications
Choose what you hear about
Saved automatically
body="flush"
Notifications
Choose what you hear about
Saved automatically
body="divided"
Notifications
Choose what you hear about
Saved automatically
body="separated"
Notifications
Choose what you hear about
Saved automatically
body="divided" divider="inset"
Notifications
Choose what you hear about
Saved automatically
On a tinted card, panels and bands are raised instead of recessed
variant="muted" body="inset"
Notifications
Choose what you hear about
Saved automatically
variant="muted" body="flush"
Notifications
Choose what you hear about
Saved automatically
variant="muted" body="separated"
Notifications
Choose what you hear about
Saved automatically
A bleeding table: rows edge to edge, content lined up with the card
Past transactions
| Payee | Category | Amount |
|---|---|---|
| Kopi Kenangan | Dining | −Rp 48.000 |
| Lintas Cargo | Payroll | +Rp 12.500.000 |
| Pasar Baru | Groceries | −Rp 320.000 |
| Vidio | Subscriptions | −Rp 39.000 |
Bleed: media out to the card's edges
Orders, May to September
Orders, May to September
A header outside a card, and sub-sections inside a body
Billing
Pro plan
Rp 240.000 per month, renews 12 October
Payment method
Bank transfer, BCA ending 4242
DefaultInvoices are emailed to billing@example.com
Card
A container for related content, such as a form, a list or a summary. Give it a header, a body and a footer, and the card handles the spacing and the dividers between them. The structure and naming follow Flux’s card; the look is Normal UI’s.
Consumer provides: the parts and their content, a heading level that fits the page outline, and as="section" or as="article" only when the card is a real section of the page.
Parts
Card.Header: aCard.Heading, an optionalCard.Subheadingand optionalCard.Actions. Actions written after the heading sit at the end of the row; written before it, at the start. They line up with the heading instead of making the header taller.Card.Body: the main content, spaced by gap. A header or footer inside the body becomes a bare sub-section, whatever the card’s treatment.Card.Footer: supporting text (ingray-text, 0.875rem) and optionalCard.Actionsat the end.Card.Bleed: media run out to the card’s edges. It reaches the sides always, and the top or bottom when it is first or last in the body.<Table bleed>in a body runs its rows to the card’s edges with lines between rows only, and lines its first and last cells up with the card’s content.- Anything placed straight inside a card without parts is padded evenly.
Props
variant:defaultis a 1pxcontrol-borderbox oncanvas, for primary content.muted(surface-muted) is quieter, for secondary panels.soft(surface-soft) is the faintest tint, for light grouping.outlinekeeps the border with no background.filledis asurface-mutedtint with no edge, for inline surfaces; it draws its border back in forced-colours mode.body: how the parts are set apart.seamless(default) shares one surface, separated by space.insetsets the body in a bordered panel inside the card’s padding.flushruns that panel to the card’s sides between two full-width lines.divideddrawsrulelines between header, body and footer; adddivider="inset"to stop the lines at the content’s edges.separatedsets the header and footer in tinted bands.- Panels and bands are recessed (
surface-muted) on a plain card and raised (surface-raised) on a tinted one, so they always stand apart from the card. size:xs,sm,md(default),lgscale the padding and the space between parts: 8, 12, 16 and 24px.
What is different from Flux, and why
- No shadows, no rounded corners, no
highlight: the system draws edges with borders, rounds only controls, and adds nothing for decoration. The inset panel keeps a 1pxruleborder as well as its tint, because the light tints are deliberately faint. - Tints come from the three
surface-*tokens only. They are as dark as light mode allows (and as light as dark mode allows) whilegray-text, links and control borders keep their contrast on them, so every component can sit on any card.
Accessibility
- The card is a plain
divby default: most cards are not sections, and too many regions make the landmarks list useless. Withas="section"oras="article"it becomes a region named by itsCard.Heading. - Pick the heading
levelfrom the page outline (h2 under the page h1, h3 for cards inside a section). Sizes are separate from levels. - Icon-only actions need an
aria-label(“More options”).
Plain HTML
patterns.css has the same card for hand-written markup: classes for the parts, data attributes for the props. Actions always sit at the end of a header here.
Delivery
Where we send your orders
Jl. Braga No. 12, Bandung 40111
| Order | Courier | Status |
|---|---|---|
| #1048 | JNE | Delivered |
| #1047 | SiCepat | On its way |
<div class="pd-card" data-body="separated" data-variant="muted">
<div class="pd-card-header">
<h3>Delivery</h3>
<p class="pd-card-subheading">Where we send your orders</p>
<div class="pd-card-actions"><button type="button">Edit</button></div>
</div>
<div class="pd-card-body">
<p>Jl. Braga No. 12, Bandung 40111</p>
<div class="pd-card-bleed"><table>…</table></div>
</div>
<div class="pd-card-footer">
<p>Updated today</p>
<div class="pd-card-actions"><button type="button">Track</button></div>
</div>
</div>
Composition
React
import { Card } from '@imsus/normal-ui-react';
<Card body="inset" size="lg">
<Card.Header>
<Card.Heading level={2}>Profile</Card.Heading>
<Card.Subheading>This is how others will see you</Card.Subheading>
<Card.Actions><Button square aria-label="More options">⋯</Button></Card.Actions>
</Card.Header>
<Card.Body>
<TextField label="Name" />
</Card.Body>
<Card.Footer>
<p>Last saved 2 minutes ago</p>
<Card.Actions><Button>Cancel</Button><Button type="submit">Save</Button></Card.Actions>
</Card.Footer>
</Card>