Card
A surface that groups related content and actions.
Preview
Family Floater Plan
Renews on 1 April 2027
Installation
pnpm add @syntara/react @syntara/tokensimport { Card, CardMedia, CardHeader, CardTitle, CardDescription, CardAction, CardContent, CardFooter } from '@syntara/react';Usage
import { Button, Card, CardContent, CardDescription, CardFooter, CardHeader, CardTitle } from '@syntara/react';
export function PlanCard() {
return (
<Card>
<CardHeader>
<CardTitle>Family plan</CardTitle>
<CardDescription>Renews on 1 April</CardDescription>
</CardHeader>
<CardContent>4 members covered</CardContent>
<CardFooter>
<Button size="sm">Manage plan</Button>
</CardFooter>
</Card>
);
}Examples
Feature
A promo card: brand glow from the top-start corner, rim light, star field, and a primary and secondary action.
Your whole portfolio, in one place
Track savings, cards and investments together, and move money between them in seconds.
Showcase
A case-study card: media on a brand glow, a title and body, three editorial figures, a footnote and a footer rail with the year and a link.
Claims · Member app
A claim form that fills itself in from the receipt
Members retyped every bill by hand and gave up halfway. Now a photo of the receipt fills the form, and they only check it.
- time to file
- −42%
- median claim
- 3 min
- filed online
- +11%
Measured in production, first quarter after launch
Showcase grid
Three interactive showcase cards in a row, one per glow (brand, accent, none). The rails line up at the bottom.
Renewals in one tap
A reminder that opens straight on the renewal, already filled in.
One wallet for the family
Shared limits that every member can see, with nobody asking who spent what.
Answers before a ticket
Search that reads the policy, so most questions end on the first screen.
With a form
Fields in CardContent and submit/cancel in CardFooter.
Variants
default (raised), outline and ghost.
Default
Raised surface with a border and shadow.
Outline
Border only, for dense layouts.
Ghost
No chrome, keeps the spacing.
Interactive
Cards that open something: one link in the title covers the card, which lifts under the pointer.
Health cover
Hospital stays, day care and check-ups for the family.
Travel cover
Medical emergencies, lost bags and trip delays abroad.
Inset content
A pale inner surface with a concentric corner, and a meta line with an icon.
Order summary refactor
feature/summary · 3 files
- src/checkout/summary.tsx+42 −8
- src/checkout/totals.ts+11 −3
- src/checkout/summary.test.tsx+27
Rim light
Rim light: the edge catches light at the top-left and fades. Built into default cards in dark; the rim prop adds it in light.
Default
A hairline edge in light; in dark the rim is built in.
With rim
The edge catches light at the top-left, in light too.
Accessibility
No keyboard interaction of its own.
- A card is a plain div; CardTitle is a real heading (h3 by default).
- If the whole card is a link, put the link on the title and extend its hit area with CSS rather than wrapping the card in <a>.
- Give a card role="region" and aria-labelledby only when it is a major page landmark.
- Interactive cards: the title link is the only tab stop for the card and names it; its focus ring is drawn round the whole card. Keep other controls inside few — they stay separately focusable above the stretched link.
- Feature cards: the glow strength (16% light, 30% dark) and star alpha are capped so text.default, text.subtle and text.brand reach 4.5:1 on the worst pixel for every tenant; test/card.test.tsx re-proves it from the CSS. Buttons on it keep their own solved fills.
- Showcase cards: text sits only on the solid face (surface.raised light, surface.sunken dark), never on the glow. CardMedia's glow is a pseudo-element, so assistive tech never meets it; what's inside CardMedia needs its own text alternative (img alt, or role="img" + aria-label on a mock).
- Editorial figures inside a showcase card (StatTile variant="editorial" in a StatTileGroup) are one <dl>: each label is read before its value, although the value is drawn first.
Guidelines
Do
- Keep one primary action per card, in the footer or CardAction.
- Let parts that must bleed (tables, images) drop their inline padding.
- Use CardContent variant="inset" when the content is one object (a table, a diff, a list) that should read as a unit inside the card.
- Use variant="feature" for one promo or hero card per view, with one primary and one secondary action.
- Use variant="showcase" for case studies and galleries: CardMedia first, then the header, the figures, a footnote and a CardFooter divider rail with meta text and one Link (standalone, trailing IconArrowUpRight).
Don’t
- Don't nest cards; use a Separator or an outline card inside.
- Don't put more than one heading level inside a CardHeader.
- Don't nest inset surfaces, or put an inset surface in an outline or ghost card: the pale fill needs the raised card around it.
- Don't put text colours other than text.default, text.subtle and text.brand on a feature card; other roles aren't proved on the glow.
- Don't put text or controls inside CardMedia, or rebuild the glow behind the header: the glow's contrast is not proven for text.
API reference
Card
variantdefaultdefaultoutlineghostfeatureshowcase
default = raised surface, hairline edge and soft shadow, plus the sheen (a diagonal band of light) and the rim light in dark; outline = hairline edge only; ghost = no chrome, same spacing; feature = a promo/hero card with a deep brand glow from the top-start corner, the rim light and the brand halo (one per view). Its glow is capped so text.default, text.subtle and text.brand stay ≥ 4.5:1 (proved in test/card.test.tsx). feature adapts to the scheme: in light it's the raised shadow and a very faint brand gradient; in dark, a deep gradient and the brand halo. showcase = a case-study card: a quiet solid face (surface.raised in light with the raised shadow; surface.sunken in dark), 1.6× the container radius (capped at space-10), a glossy rim brightest along the top, and a CardMedia on top. Its text (text.default, text.subtle, text.brand) is proved on the face and the sheen for tenants and 1,000 fuzz brands (test/card.test.tsx). Parts inside get a concentric radius. With interactive it lifts 2px.
interactivebooleanFor cards that open something. One link in CardTitle stretches over the card; the card lifts on hover, springs back when pressed, and shows the focus ring round the whole card. Other controls inside stay clickable.
Default
falserimbooleanRim light: the 1px edge is brighter at the top-left and fades, like light catching glass. Built into default cards in dark (the surface recipe); rim adds it in light and to outline and ghost cards. Always on for variant="feature".
Default
falsestarsbooleanA faint decorative star field (CSS dots in a pseudo-element, invisible to assistive tech). Only drawn on variant="feature".
Default
false
CardMedia
glowbranddefaultaccentnone
The ambient haze behind the media, rising from the bottom centre and fading into the card face: brand = action.primary.bg, accent = accent.bg. Decorative (a pseudo-element), and only ever behind the media: CardMedia is the only part that draws it.
childrenReactNodeAn image, video or device mock, centred. Edge to edge at the top of the card and clipped to its top corners; put it first. Give images their own alt text; a mock built from divs needs role="img" and an aria-label. No text content: the glow isn't proven for text.
CardHeader
dividerbooleanDraws a hairline under the header.
Default
false
CardTitle
level1 | 2 | 3 | 4 | 5 | 6Heading level. Pick the one that fits the page outline.
Default
3
CardAction
childrenReactNodePlaced at the top inline-end of the header, beside the title and description (e.g. a Badge, Link or menu button).
CardFooter
dividerbooleanDraws a hairline above the footer.
Default
false
CardContent
variantdefaultdefaultinset
inset = a pale inner surface (surface.sunken, hairline edge, corner concentric with the card) for a table, list or code block. A table inside fills it edge to edge and loses its own frame; the card inset token is halved inside.
Tokens
The semantic tokens this component reads, grouped by what they control. Swatches show this site’s theme; change a tenant’s brand and the component follows with no code change.
- Colour10
border.defaultborder.subtlefocus.ringsurface.raisedtext.defaulttext.subtlesurface.sunkenaction.primary.bgtext.brandaccent.bg- Type14
font.bodyfont.headingfont.size.lgfont.size.mdfont.size.smfont.weight.semiboldline-height.normalline-height.tightfont.tracking.lgfont.tracking.mdfont.tracking.smfont.weight.regularfont.size.xlfont.tracking.xl- Space and size7
space.1space.2space.4card-inseticon-strokespace.3space.10- Shape2
radius.containerradius.badge- Depth3
shadow.overlayshadow.raisedhairline- Motion7
motion.duration.fastmotion.duration.normalmotion.duration.springmotion.easingmotion.springmotion.duration.slowmotion.easingOut- Other3
rimsheenglow