Brik Design System
Components

Card

Flexible content container with composable subcomponents and two locked-down presets (control + summary).

Card is the canonical content-grouping container. Three rendering modes:

  • Default — flexible container, compose with CardTitle / CardDescription / CardFooter subcomponents.
  • preset="control" — locked-down settings/control layout (badge + title + description + action). Replaces the legacy CardControl component per ADR-004.
  • preset="summary" — compact metric/stat layout (label + large value + optional link). Replaces the deprecated CardSummary component.

Use it for

  • Service grids, feature cards, and content blocks (default mode)
  • Settings panels with title + description + toggle/action (preset="control")
  • Dashboard stat tiles ($48K Q1 revenue, 142 active users) (preset="summary")
  • Any grouped-content surface where consistent border/padding/shadow matter

For a horizontal stack of card-like rows, use FieldGrid wrapping Cards. For loading-state placeholders, use Skeleton variant="rectangular".

Import

import { Card, CardTitle, CardDescription, CardFooter } from '@brikdesigns/bds';

Default mode

Compose freely with the Title / Description / Footer subcomponents.

<Card variant="outlined" padding="md">
  <CardTitle>Title</CardTitle>
  <CardDescription>Description text goes here.</CardDescription>
  <CardFooter>
    <Button variant="primary" size="sm">Action</Button>
  </CardFooter>
</Card>

Variants

  • outlined (default) — Subtle secondary border.
  • brand — Primary-color border for emphasis.
  • elevated — Shadow for visual prominence.

Padding

none, sm, md (default), lg. Match content density.

interactive adds hover affordance. href renders as an <a> so the whole card becomes a link.

<Card variant="elevated" interactive>
  Hover me
</Card>

<Card href="/articles/foo" interactive>
  Whole card is a link
</Card>

Control preset

preset="control" is the canonical settings-row card. Locked layout: leading badge + (title + description) on the left, action slot on the right.

<Card
  preset="control"
  badge={<Badge status="positive">On</Badge>}
  title="Email notifications"
  description="Send a weekly digest to your inbox."
  action={<Button variant="outline" size="sm">Configure</Button>}
/>

actionAlign controls vertical alignment of the action slot — center (default) or top (anchors to the upper-right when descriptions are tall).

Both <Card preset="control"> and standalone <CardControl> ship as first-class APIs in v0.39.0+. The 2026-Q2 audit recommended folding CardControl into Card; the user reversed that decision 2026-04-24 to preserve optionality at the call site. Pick whichever reads cleaner in context. See the audit doc.

Summary preset

preset="summary" is the compact stat tile. Label on top, large numeric value below, optional text link.

<Card
  preset="summary"
  label="Q1 revenue"
  value={48250.75}
  type="price"
  textLink={{ label: 'Details', href: '/revenue' }}
/>

Number formatting

  • type="numeric" (default) — locale-formatted integer (1,234).
  • type="price" — USD currency ($1,234.50).
  • String values render verbatim regardless of type.

The standalone CardSummary component is @deprecated and slated for deletion in a future major version. Migrate to Card preset="summary" — same prop names, same number formatting, same layout. See ADR-004.

When not to use

  • Don't use Card for inline content blocks. Cards imply discrete grouping; for paragraphs and section dividers, use prose + Divider.
  • Don't use Card for tables. Use a table component when rows share columns. Cards are for self-contained groupings.
  • Don't reach for the default mode when preset="control" or preset="summary" fits. The presets carry locked-down semantics that propagate consistently across screens.

Accessibility

  • Default Card renders a <div>; with href, it renders an <a> with full anchor semantics (right-click, keyboard, screen-reader link role).
  • interactive without href adds role="button" only when onClick is also passed; otherwise it's a non-interactive hover affordance.
  • Title becomes an <h3> semantic by default in the Title subcomponent — adjust the surrounding heading hierarchy accordingly.

API

Default mode

PropTypeDefault
variant'outlined' | 'brand' | 'elevated''outlined'
padding'none' | 'sm' | 'md' | 'lg''md'
interactivebooleanfalse
hrefstring
childrenReactNode (required)

Control preset

PropTypeDefault
preset'control' (required)
titlestring (required)
descriptionstring
badgeReactNode
actionReactNode
actionAlign'center' | 'top''center'

Summary preset

PropTypeDefault
preset'summary' (required)
labelstring (required)
valuestring | number (required)
type'numeric' | 'price''numeric'
textLink{ label: string; href: string }

All modes accept standard <div> HTML attributes (excluding title, which is repurposed in the control preset).

On this page