Skip to content

Cards

components specs/components/cards.kmd

Card — a container of related content + actions, typically clickable as a whole. Material parity (`/components/cards`). 3 variants (elevated, filled, outlined), uniform anatomy, and rules for composition with images, lists, and feeds.

When this spec applies

Primary triggers

All triggers

Specification body

Spec — Cards

Facet Visual do Koder Design. Material parity: https://m3.material.io/components/cards.

3 card variants

VariantVisualUse
ElevatedSurface bg + shadow level 1Default — slight depth, draws attention
FilledSurface-variant bg + no shadowLess emphasis; for embedded cards within a denser context
OutlinedTransparent bg + 1px accent borderHigh structure, low visual weight (forms with grouped fields)

Anatomy

┌──────────────────────────────┐
│  [Optional media]            │   ← image / video / illustration
│                              │
│  Title (title-large)         │
│  Subtitle (body-medium muted)│
│                              │
│  Body content                │
│                              │
│  [Action 1] [Action 2]       │   ← optional actions
└──────────────────────────────┘
  • Container: radius-md, padding 16-24 px
  • Media (optional): full-width image, aspect 16:9 default
  • Title: title-large (22/28, weight 600)
  • Subtitle: body-medium (14/20) in text-muted
  • Body: body-medium
  • Actions: button row, right-aligned (or left in RTL)

R1 — Card density

DensityPaddingUse
Comfortable24 pxDefault — feeds, dashboards
Compact16 pxDense lists (table cards, multi-column grids)
Spacious32 pxHero cards (single card per fold)

Density follows themes/ui-style.kmd preset's density token; can be explicitly overridden per card via class modifier.

R2 — Clickable card

Most cards are clickable as a whole (navigate to detail).

  • Entire card surface is the hit area
  • Hover state: subtle elevation boost (+1 level) OR background tint
  • Focus ring: 2 px on outer container (per interaction/states.kmd)
  • role="link" if it navigates; role="button" if it triggers an action
  • Inner buttons are stop-propagation: clicking them doesn't trigger the card's main action
  • Cursor: pointer on whole card

R3 — Compositions

Feed item card

Used in vertical scrollable feeds (per canonical-layouts.kmd L1).

  • Compact density
  • Title + subtitle + 1-3 lines of body
  • Optional avatar (40 px) + author name + timestamp
  • Click navigates to detail

Product card

  • Elevated variant
  • Hero image (16:9 or 1:1)
  • Title + price + rating
  • "Add to cart" or similar primary action
  • Hover: shadow boost + slight scale (1.02)

List-detail card

  • Outlined or Filled variant
  • Selected state: accent-tinted bg + accent border (1.5 px)
  • Used in list-detail layout (per L2)

Stats card (dashboard)

  • Outlined variant
  • Large numeric value (headline-large)
  • Label (title-small muted)
  • Optional sparkline / mini-chart

R4 — Cards within cards

Anti-pattern. A card MUST NOT contain another card. If nesting feels needed, the inner content should be a list-item, expansion-panel, or embedded section — not a card.

Exception: a card containing one image-card preview (e.g., a tweet embed inside a notification card) — allowed because the inner is a quoted/embedded artifact, not a peer container.

R5 — Media handling

  • Aspect ratio: 16:9 (default), 1:1 (square avatar/product), 4:3 (legacy)
  • Loading: skeleton placeholder matches final aspect (no layout shift)
  • Failure: fallback to surface-variant bg + icon
  • Alt text: alt attribute REQUIRED for non-decorative images
  • Lazy-loading: loading="lazy" for cards below the fold

R6 — Per-preset variation

PresetVariant emphasis
material3Elevated default (subtle shadow)
material2Stronger shadows, sharper corners
windows_11Mica backdrop blur on Elevated
windows_953D bevel border instead of shadow; sharp corners
glassmorphismTranslucent + backdrop blur
brutalistOutlined only (no shadows, thick border)
neumorphismSoft inverse shadow (looks "pressed into" surface)
dieter_ramsOutlined default; minimal ornament

R7 — Accessibility

  • Card title is a heading (<h2>-<h4> depending on page level)
  • Clickable card focus ring on outer container only (not on title)
  • Inner buttons reachable by Tab (separately from card focus)
  • Reading order matches visual order (DOM = visual)

R8 — Forbidden patterns

  • ❌ Card without title (just a body of text) — use a <section> instead
  • ❌ Multiple primary actions in card actions row (1 primary, N secondary)
  • ❌ Card with no border + no shadow + no bg variation (use a plain <div>)
  • ❌ Animations that change card height on hover (causes feed shift)
  • app-layout/canonical-layouts.kmd — feed (L1) uses cards
  • themes/elevation.kmd — Elevated variant level 1 default
  • themes/shape.kmd — radius-md container
  • interaction/states.kmd — hover/focus per card type
  • foundations/elements.kmd — Container family

References