Card
The stream-level container drawn as a code window: a step off the page, a 7% hairline, never a shadow; a window variant with a title bar.
import { Card, CardHeader, CardTitle and 5 more } from "@arcadia/ui"A card is a code window: one step off the page on --bg-card, framed by a 7% hairline with continuous corners, and it never casts a shadow: it is part of the page, not floating over it. Put rows in CardRows (ListRows inset 6px), prose in CardBody, a title and meta in CardHeader, and actions in CardFooter.
Examples
Interactive header
With interactive, the whole header is one button: a disclosure, or a way to open the plan. Don't nest other buttons in it; a static header with CardMeta can hold them instead.
A form
render turns the card into the <form> itself, so the footer's buttons submit and reset it natively.
Window
variant="window" makes the first header a title bar: the file in mono (its name in text-1, the folder in text-3), stats and actions at the end and always shown, and a hairline below.
A file and its diff read as one object.
rootStyle takes where the card sits and these knobs; the header, body, rows and footer read them too, so --card-px moves every part's padding at once.
--card-bg- PaintDefault var(--bg-card)
- The card's surface.
--card-border- PaintDefault var(--stroke-3)
- The 1px frame.
--card-radius- Ref<Radius>Default var(--radius-frame-card)
- Corner radius (the card frame, 15; a nested card takes its rows' corner).
--card-corner- Ref<"--corner"> | "round"Default var(--corner)
- Corner shape: continuous where supported, round on a nested card.
--card-px- Ref<Space>Default var(--space-3)
- Inline padding of the header, body and footer.
--card-bar-h- Ref<Control>Default var(--control-lg)
- A window's title bar height.
--card-header-gap- Ref<Space>Default var(--space-1-5)
- Gap between a header's items.
Rows inside CardRows subtract their 6px inset and the border from the card radius, keeping the same corner shape.
A card is a plain <div> with no role; its parts are text and the controls you put in them. The one exception is an interactive header, which renders a <button>: give it aria-expanded when it discloses the body, as above, and keep its text short, because the whole header is its name.
When a card is a section people navigate to, give it a heading or role="region" with aria-labelledby on its title. Diff counts are colour and text, so "+14 −3" still reads without the colour.
- EnterSpace
- Activates an interactive header
- Tab
- Moves through the controls inside
Card
level- "stream" | "nested"Default "stream"
stream: a turn-level card, 15, continuous corners.nested: inside a card or row, round, concentric with its rows.variant- "default" | "inset" | "window"Default "default"
inset: a well, the page seen through the frame.window: its firstCardHeaderis a title bar (mono, a hairline below).mono- booleanDefault false
- Code inside:
--type-code, untracked. rootStyle- CardStyle
- Typed StyleX override: where the card sits and its
--card-*knobs.
Rest props go to <div> props and render.
interactive- booleanDefault false
- The whole header is one
buttonwith a hover fill (a disclosure); no other buttons inside it. divided- booleanDefault false
- Hairline under the header (a body follows).
Rest props go to <div> props and render.
divided- booleanDefault false
Rest props go to <div> props and render.
link- boolean
- A link (
render={<a />}): underlined under the pointer. rootStyle- stylex.StyleXStyles<Omit<Layout, "maxWidth"> & { maxWidth?: Layout["maxWidth"] | `${number}%` }>
- Layout;
maxWidthmay be a percentage.
Rest props go to <span> props and render.
shown- booleanDefault false
- Always in sight.
Rest props go to <div> props and render.
No props of its own. Rest props go to <span> props and render.
No props of its own. Rest props go to <div> props and render.
No props of its own. Rest props go to <div> props and render.