Card
A bordered content panel — a header (title + description), a body, and an
optional footer. Card is static chrome: a flat surface with a hairline
border and no shadow (elevation is reserved for floating layers like menus
and dialogs). It has no interactivity of its own.
For a label/control list, use BasicPage.Card; for a featured block
on the page surface (an invitation form, a notice), use BasicPage.Callout.
Import
import { Card } from "@photon-ai/pho-ui/components/card";
Usage
The Root carries the vertical padding (pt-5 / pb-4) and the rhythm
between parts (gap-4); Header, Content, and Footer carry the horizontal
padding. The footer is unopinionated about justification — add
justify-end for a dialog-style action bar.
Usage
Data since Aug 1.
<Card.Root>
<Card.Header>
<Card.Title>Usage</Card.Title>
<Card.Description>Data since Aug 1.</Card.Description>
</Card.Header>
<Card.Content>…</Card.Content>
<Card.Footer className="justify-end">
<Button size="sm" variant="outlined">
Upgrade
</Button>
</Card.Footer>
</Card.Root>
Content only
Every part is optional — the Root alone is a valid surface.
<Card.Root>
<Card.Content>A card can be just the surface.</Card.Content>
</Card.Root>
Full-bleed children
Because only the parts carry px-5, a direct child of the Root with no
padding of its own — an image, a table, a Separator — runs edge-to-edge:
<Card.Root>
<Card.Content>…</Card.Content>
<Separator />
<Card.Footer>…</Card.Footer>
</Card.Root>
Parts
All parts render plain elements and forward every native attribute.
- Card.Root —
<div>— the bordered surface; vertical padding and part rhythm live here - Card.Header —
<div>— keeps the title/description pair tight - Card.Title —
<h3>— the card heading - Card.Description —
<p>— supporting copy in the secondary tone - Card.Content —
<div>— the body; bring your own layout - Card.Footer —
<div>— trailing row for actions or a status line
The CARD_SURFACE class string is also exported, for hosts that need the
surface look on another element.
Accessibility
- Semantics — a card is a generic
<div>with no ARIA role. If it stands alone as a page landmark, passrole="region"and anaria-label(or pointaria-labelledbyat the title’sid); a card in a list usually needs neither. - Heading level —
Card.Titlerenders an<h3>so it nests under a pageh1and sectionh2without skipping levels. Keep the document outline in mind when placing cards. - Not interactive — the surface never takes focus. If the whole card should be clickable, put a link inside the title and stretch its hit area, rather than wrapping the card in a button.
Best practices
- One subject per card. When a card starts growing sections, that’s a page layout, not a card.
- Don’t nest cards. A bordered panel inside a bordered panel reads as noise —
inside a card, separate with spacing or a
Separator. - Cards sit on the page background; don’t stack them on another raised surface.
- Keep the footer for trailing actions or status, not for more content.