flyingsalmon

Card

A flat container that groups related content on one surface. You compose what goes inside; the card fixes only the edge, the padding, and the interaction feedback.

Slots

Seven slots: Card, CardHeader, CardTitle, CardDescription, CardAction, CardContent, and CardFooter. Use the ones you need. There is no variant and no size — width comes from your layout, and the one padding step is --card-spacing. CardAction is a direct child of Card, not of the header: it pins to the bottom right so the action never competes with the title for the top edge.

Light
Weekend in Kyoto
Three days, ten stops
Temples in the morning, tea in the afternoon, a river walk at dusk.
Updated today
Dark
Weekend in Kyoto
Three days, ten stops
Temples in the morning, tea in the afternoon, a river walk at dusk.
Updated today

Flat, never raised

The card separates from the page with a solid 1px border and a surface step, never a shadow. Dark mode lifts --card above --background instead of adding depth. The system ships no shadow tokens at all.

Interactive

Pass interactive and render the link as the direct child of CardTitle. The link stretches its hit area over the whole card through a pseudo-element, so a click anywhere follows it. The card itself is not a link, so a nested button stays valid HTML and stays independently clickable.

Light
Three days, ten stops
Temples in the morning, tea in the afternoon, a river walk at dusk.
Dark
Three days, ten stops
Temples in the morning, tea in the afternoon, a river walk at dusk.

States

A static card has one state. An interactive card has four: rest, hover, focus-visible, and pressed. There is no disabled state — a dead target must not render as an almost-clickable card. There is no loading state either; use skeleton while the content is missing.

Motion

Hover turns the border indigo. Press grows a 2px --primary ring out of nothing while held, matching the button. Focus draws a 2px --ring ring around the whole card boundary. All three are CSS transitions at --motion-fast. The card owns no other motion — list enter, exit, and reorder belong to your app through motion’s layout prop.

Accessibility

An interactive card takes one Tab stop, the title link, and Enter activates it. A nested action takes its own Tab stop after it. The screen reader hears the title as the link name, not the whole card. The focus ring meets 3:1 against both the card and the page; the card border is decorative, so the content identifies the card.