apx-dsv0.1Local renderer · live
K
Foundations4
  • Getting started
  • Theming
  • Templates
  • Icons
  • Avatar
  • Badge
  • DataGrid
  • Scheduler
  • Stat
  • Table
  • Timeline
  • TreeView
  • Accordion
  • Alert
  • EmptyState
  • Progress
  • Skeleton
  • Spinner
  • SplashScreen
  • Toast
  • ColorPicker
  • FileUpload
  • Form
  • Rating
  • TagsInput
  • Combobox
  • Field
  • Select
  • Toggle
  • Button
  • Calendar
  • Checkbox
  • DatePicker
  • Input
  • NumberInput
  • Radio
  • Slider
  • Switch
  • Textarea
  • AppShell
  • Div
  • Divider
  • Sidebar
  • Stack
  • Typography
  • Image
  • Breadcrumbs
  • Carousel
  • NavigationMenu
  • Pagination
  • Stepper
  • Tabs
  • Toolbar
  • CommandPalette
  • Confirm
  • Drawer
  • HoverCard
  • Menu
  • Modal
  • Popover
  • Tooltip
  • Icon
  • Card
  • PricingCard
60 componentsapx-ds/renderer
Card
Variant↳ other

Surfaces

Card

Compound content container. Root + Header / Body / Footer / Media / Divider subparts, with optional whole-card click, hover lift, selection ring, and horizontal

Card

<Card /> is the canonical content container in apx-ds, and the first compound component in the library. The root paints the shell; five subparts (Card.Header, Card.Body, Card.Footer, Card.Media, Card.Divider) compose the inside.

Reach for Card whenever a piece of UI needs an edge, a background, and a stack of regions: project tiles, search results, settings groups, dashboard widgets, the inside of a Modal.

Overview — header, body, and footer in one tile

Loading preview…
Overview.tsx

Compound API

<Card.Header> has dedicated slots (avatar, title, subtitle, action) instead of asking consumers to hand-author a flex row. That's deliberate — title/subtitle pairs are the most overlooked source of accessibility regressions in DS cards. Pass title={<h3>...</h3>} if a heading level is needed; the slot renders as a <div> by default so the Card doesn't blindly inject itself into the page outline.

Pass icon to opt into the icon-led feature layout — an opinionated icon tile is rendered above the title row, with a tile size + corner radius + icon-to-title gap all derived from the Card's size context. iconColor (any palette role) and iconVariant (soft / solid / outline) drive the tile's tint. Use this whenever you'd otherwise hand-roll a <span> wrapper for a marketing / feature / pricing card.

Variants

  • outline — bg-bg-paper + 1px border. Default. The conventional card.
  • solid — quiet, edgeless, bg-bg-subtle. Pairs well with dense layouts.
  • elevated — bg-bg-paper + shadow-md. For surfaced content; what a Modal looks like.
  • ghost — no edge, no fill. Container only when hovered (combine with hoverable).

Color

color does not repaint the body — that would shout for attention. Instead it drives two accents:

  • hoverable={true} → border tints to the role color on hover.
  • selected={true} → a colored ring + data-selected="true".

Same accent shows up on the focus ring when clickable. Adding a new palette role re-paints every accent automatically; no Card-side changes.

Interactivity

  • hoverable — pure cosmetic lift (transform + shadow). Does not imply a click target.
  • clickable — promotes the entire card to a single click target. The root gets role="button", tabIndex=0, and keyboard activation (Enter / Space). Pair with onClick.
  • disabled — dims the surface, blocks pointer events, sets aria-disabled="true".
  • selected — toggles the colored ring + data-selected="true" for multi-select grids.

For more complex semantics (a link Card, a <button> Card with <form> integration), reach for asChild. The wrapped element's role wins (link for <a>, button for <button>), and Card still contributes its frame + keyboard wiring.

Orientation

horizontal puts Card.Media at the logical start of the row, so RTL layouts auto-mirror. The media slot is width-fixed at 2/5; the body takes the rest.

Sizes & padding

Density lives on the root and propagates to every subpart via CardContext. Set size="lg" once and Header / Body / Footer all jump to p-6. Subparts never expose their own size prop — they read it from the parent.

Examples

Basic — Header + Body

Loading preview…
Basic.tsx

Variants — outline / solid / elevated / ghost

Loading preview…
Variants.tsx

Sizes — sm / md / lg propagate via context

Loading preview…
Sizes.tsx

Colors — selected ring + hover border tint

Loading preview…
Colors.tsx

Shapes — square / rounded / pill

Loading preview…
Shapes.tsx

With media — Card.Media + aspect ratio

Loading preview…
WithMedia.tsx

Horizontal — media on the side

Loading preview…
Horizontal.tsx

Header slots — avatar / title / subtitle / action

Loading preview…
HeaderSlots.tsx

Icon header — feature card with stacked icon tile

Loading preview…
IconHeader.tsx

Footer alignment — start / center / end / between

Loading preview…
FooterAlignment.tsx

Clickable — whole-card click target

Loading preview…
Clickable.tsx

Selectable — multi-card selection grid

Loading preview…
Selectable.tsx

asChild — render Card as a link

Loading preview…
AsChild.tsx

With divider — semantic section breaks

Loading preview…
WithDivider.tsx

Theming

Card pushes the per-slot override path harder than any other component to date — each of the six slot keys (root, header, body, footer, media, divider) merges independently through useThemedClasses — overrides on header don't bleed into footer, and consumer className still wins last via tailwind-merge.

Accessibility

  • Non-interactive Card: plain <div>, no role. Content reads in normal order.
  • clickable: role="button", focusable, Enter / Space activate. Focus ring tints by color.
  • disabled: aria-disabled="true" + pointer events blocked. Not focusable.
  • Card.Header.title is not a heading by default — pass <h2>...</h2> if needed.
  • Card.Media requires alt when src is set (dev-warn if missing); pass alt="" for decorative imagery.
  • axe-core: zero violations across the matrix.

Compound-component pattern

Card/index.ts is the canonical assembly file for every future compound primitive in the DS. The root component is wrapped with Object.assign so subparts are reachable via dot syntax (<Card.Header>, <Card.Body>, …). Tabs, Accordion, Modal, Drawer all copy this shape. Consumers reach subparts via <Card.Header> — no separate import, no naming friction.

Props

PropTypeDefaultDescription
asChildboolean—Radix-style polymorphism. Merges Card's props onto a single child element (e.g. wrap an `<a>` to render an entire-card link). The child's natural role wins (e.g. `link` for `<a>`).
clickableboolean—Makes the whole card a single click target. Wires `role="button"`, `tabIndex=0`, and keyboard activation (Enter / Space) — no need to wrap in `<button>` manually.
colorenum'neutral'Palette role used by `selected` + `hoverable` accents.
disabledboolean—Dims the card and blocks pointer events. Adds `aria-disabled` for SR users.
hoverableboolean—Lifts the card on hover (transform + shadow). Pure cosmetic; does not imply clickability.
orientationResponsiveValue<CardOrientation>'vertical'Layout direction — vertical stacks, horizontal puts Media on the side.
selectedboolean—Visually marks the card as the active item in a multi-select context. Adds a colored ring + `data-selected="true"`. Does not alter focus/role.
shapeenum'rounded'Corner radius family.
sizeResponsiveValue<CardSize>'md'Padding density propagated to every subpart via context.
sxSx—Theme-aware inline style object.
variantResponsiveValue<CardVariant>'outline'Edge + background style.