Skip to main content

What it is

A bordered container that groups related content into one recognizable unit, with three optional states — interactive, selected, and error — expressed as CSS classes and data-* attributes on top of the underlying element’s own Card.

Live example

Exports

Vocabulary

No aliasing dispute exists between the design library and code here — both call the container a card. The three state names above are this page’s own vocabulary for the three boolean props; say selected, not “active,” for the same reason Tabs prefers it — a card can be selected while the content behind it is still loading.

Choose Card when

  • Content forms one coherent, self-contained unit a reader recognizes as a single object — a record’s summary, an option in a set, a tile in a grid.
  • The container itself needs to communicate interactive, selected, or error state through its own border or background, not just through its contents.

Choose something else when

Anatomy

CardHeader and CardActionArea are exported and render inside a Card, but carry no Titan override. Confirmed against Card.overrides.ts, whose only theme override entries are for Card, CardActions, and CardContent. Their padding and typography are unthemed defaults with no Titan decision behind them, unlike CardContent and CardActions, which use spacing-6.

Variants, sizes, and states

Hand-confirmed from Card.overrides.ts and the component’s own BasicCard/InteractiveCard stories — no per-component matrix emitter exists yet for this concept. The InteractiveCard story demonstrates interactive alone and interactive selected together. Since all three are independent booleans rather than one variant enum, they combine freely in the type system — including combinations no story or test demonstrates, such as interactive error together. There is no size prop — a Card takes whatever width or height its container or sx gives it; no small/medium scale exists.

Edge and failure states

Tokens

Hand-confirmed from Card.overrides.ts — no per-component token emitter exists yet for this concept, so this table is hand-confirmed rather than generated.

Composition

A Card’s children are otherwise unconstrained — CardContent and CardActions are the only two slots Titan themes, so anything else composed inside (a header, a media block, an avatar) renders at whatever spacing that element itself provides, not a Card-level decision.

Content

No content rules are recorded in source for Card copy. Unlike a table column header or a tag label, nothing in Card.tsx, its stories, or its tests constrains what goes inside one. Treat general copy guidance — Voice & tone, Capitalization — as what applies.

Accessibility

  • Card renders a plain container with no ARIA role of its own — confirmed neither Card.tsx nor Card.overrides.ts sets one.
  • interactive adds no keyboard affordance. Confirmed by reading Card.tsx in full: the prop only ever touches className and data-interactive. It adds no tabIndex, no role="button", and no onKeyDown handler. A keyboard user cannot activate an interactive Card unless the caller adds their own focus and key handling.
  • No accessible signal exists for selected or error beyond the border color. Confirmed: no aria-selected, aria-invalid, or equivalent attribute is set for either state. A screen reader user gets no indication a card is selected or in error — only its border color, which conveys nothing to anyone who can’t perceive it.

Constraints

Known issues

Card: open issues

Divergences, open decisions, and undocumented gaps for Card.

Why it works this way

Card’s three states are independent booleans rather than one variant enum, which is why they combine freely — the same mechanism that makes interactive selected in the InteractiveCard story straightforward to build also means nothing in the type system stops a caller from setting error and interactive together, a combination no story or override treats as a real case.

Status

Package @invoca/titan-core, version 3.6.3. Primary export: Card. CardActions and CardContent carry Titan padding; CardHeader and CardActionArea are exported but unthemed. No deprecation marker or since field is recorded for any of them. Titan’s own utilization.md records 37 usages across 11 products: ai-model-management (6), interaction-details (6), signal-validation (5), call-review-flow (4), manage-integrations (4), manage-invoca-tags (3), ai-labs (2), dashboards (2), developer-tools (2), signals (2), and intent-detection (1).
  • List — the flatter, borderless alternative for simple rows
  • Table — for many records compared attribute by attribute
  • Tag — for a single attribute label rather than a whole container
  • Skeleton — the loading placeholder several products already pair with Card
Last modified on September 7, 2026