Brik Design System
Components

Card

Flexible content container with composable subcomponents and four locked-down presets (control, summary, display, display-row).

Card is the canonical content-grouping container. Five 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).
  • preset="display" — the malleable vertical cell of a card-grid Section, per ADR-018.
  • preset="display-row" — the horizontal card-grid cell / section row (image left, content right).

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 — Surface-primary fill, no border, no shadow (flat since brik-bds#1146; for a shadow use raised).
  • raised — Surface-primary fill, no border, with a cast --box-shadow-md drop shadow. The shadow-casting counterpart to the now-flat elevated; use for a focal/lone card or a grid cell that needs a lifted, contained read.
  • borderless — Transparent fill, no border, no shadow. Use for cards sitting on a colored surface, where the border ring reads as visual noise.

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>

Leading media

The media prop turns the default card into a horizontal "media object" — an Avatar or a square 1:1 Image on the left, with children stacked to the right. Pass exactly one of avatar / image. Both size to the shared Avatar scale (sm 32px, md 40px, lg 48px, xl 64px). The avatar falls back to initials from name and can carry a presence status; the image takes fit (contain for logos, cover for photos).

<Card media={{ avatar: { name: 'Jordan Lee', status: 'online', size: 'lg' } }}>
  <CardTitle as="h4">Jordan Lee</CardTitle>
  <CardDescription>jordan.lee@brikdesigns.com</CardDescription>
</Card>

<Card media={{ image: { src: '/brik-logo.svg', alt: 'Brik Designs logo', fit: 'contain', size: 'lg' } }}>
  <CardTitle as="h4">Brik Designs</CardTitle>
  <CardDescription>Design system · Enterprise plan</CardDescription>
</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).

preset="control" replaces the standalone <CardControl> component, which is deprecated per ADR-004 (#657). New code should use the preset; see the CardControl migration guide.

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.

Display preset

preset="display" is the malleable cell of a card-grid Section, not a standalone card — per ADR-018, a display card only exists inside a grid that owns the columns. Every affordance is optional and prop-toggled so one cell serves any content type — service, blog post, customer story, property listing, team bio, support plan.

<Card
  preset="display"
  tag={<ServiceTag line="brand" />}
  image={<Frame ratio="16-9"><img src="/service.jpg" alt="" /></Frame>}
  badge={<Badge>Featured</Badge>}
  title="Brand identity"
  description="Logo, type, and color systems built to scale."
  action={<Button href="/services/branding" variant="outline" size="sm">Learn more</Button>}
/>

title renders as titleAs (default h3) — set it to keep the document outline correct under a grid-section heading; the visual size is token-driven and unchanged by the level. For a cell on a colored (service-tinted) grid, variant="borderless" (transparent), variant="elevated" (fill + shadow), or variant="raised" (fill + cast --box-shadow-md shadow) swaps the surface treatment, and tint applies a pale service-line wash. badge renders only when image is also set.

Display-row preset

preset="display-row" is the horizontal card-grid cell / section row — image on the left, content (tag, title, description, action) on the right. Use for single-row sections where a vertical layout wastes horizontal space (Related Customer Story, Recommended Add-On, featured plan). Collapses to a vertical stack at ≤ 640px.

<Card
  preset="display-row"
  tag={<Tag>Case study</Tag>}
  image={<Frame ratio="4-3"><img src="/story.jpg" alt="" /></Frame>}
  imageWidth="standard"
  title="How Northwind tripled conversions"
  description="A ground-up rebrand and site rebuild."
  action={<Button href="/stories/northwind" variant="outline" size="sm">Read the story</Button>}
/>

imageWidth sets the left column: narrow (25%), standard (35%, default), or wide (50%) — or pass any CSS length/percentage string ("40%", "320px"). The optional extras slot renders structured content (bullet lists, feature pills) between description and action.

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' | 'raised' | 'borderless''outlined'
padding'none' | 'sm' | 'md' | 'lg''md'
interactivebooleanfalse
hrefstring
mediaCardMedia (exactly one of avatar / image / logo)
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'
textLinkCardSummaryTextLink

Display preset

PropTypeDefault
preset'display' (required)
titlestring (required)
titleAs'h2' | 'h3' | 'h4''h3'
descriptionstring
variant'borderless' | 'elevated' | 'raised'
tintCardTint (service line)
imageReactNode
tagReactNode
badgeReactNode (needs image)
actionReactNode
hrefstring

Display-row preset

PropTypeDefault
preset'display-row' (required)
titlestring (required)
titleAs'h2' | 'h3' | 'h4''h3'
descriptionstring
tintCardTint (service line)
imageReactNode
imageWidthCardDisplayRowImageWidth (narrow / standard / wide, or any CSS length)'standard'
tagReactNode
extrasReactNode
actionReactNode
hrefstring

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

On this page

💬