Aurora AppKit / Supernova Handover / Card

Component handover · For all platforms

Card

A clickable container that groups related content and actions for a single subject — used in lists and grids as a navigation element or to surface key information at a glance.

Open in Figma
Version
v1.0
Released
30 Jun 2026
Scope
All platforms
Breakpoints
xs · md
Implementation
Not yet built
ℹ️ This release (v1.0). Initial release of the clickable content Card — fixed text stack (tagline / heading / subheading), inline status dot, optional badge, and three swap slots (leading, trailing, expanded body).
⚠️ Don’t confuse with CardContainer. The repos already contain a generic CardContainer control (a low-level rounded/shadowed wrapper). This new Card is a higher-level, content-structured component and is a separate build.

Summary

The Card is a clickable container that groups related content and actions for a single subject. It is used in list and grid layouts as a navigation element or to surface key information at a glance. It has a fixed text stack (tagline / heading / subHeading), an inline status dot, three optional swap slots (leading, trailing, expanded body), and an optional corner badge.

Anatomy

  • 1
    Container — rounded, shadowed root surface.
  • 2
    slotStart — leading slot before the text (40×40 icon/avatar area).
  • 3
    tagline — caption line above the heading (part of the fixed text stack).
  • 4
    Heading — primary heading.
  • 5
    Subheading — secondary line.
  • 6
    statusIndicator — inline 16×16 status dot, top-right.
  • 7
    hasBadge — notification badge overlay on the corner (e.g. “99+”), absolutely positioned.
  • 8
    slotEnd — trailing slot after the text (e.g. chevron).
  • 9
    slotContent — expanded content slot below the main row.

Properties / API

PropertyType / valuesDefaultDescription
breakpointxs · mdxsControls card width — xs 382px, md 395px. Match to your container’s responsive breakpoint.
statedefault · activedefaultactive switches the root fill white → light grey (#EDEDED) to signal selection / focus.
heightFillfalse · truefalsetrue stretches the card to fill its container height (equal-height grid / flex rows).
slotStartbooleantrueToggles the leading icon/avatar slot. false removes it from layout — no residual gap.
slotContentbooleanfalseReveals the content slot below the text stack. Only enable with a swap (empty shows a placeholder).
hasBadgebooleanfalseRenders a corner badge overlay. Absolutely positioned — does not affect card height.
hasStatusIndicatorbooleantrueShows/hides the 16×16 status dot top-right. Set false for archived/completed/offline cards.
slotEndbooleanfalseToggles the trailing slot. false removes it from layout — no residual gap.
slotStartSwapslotLeading icon/avatar (40×40). Governed by slotStart.
slotEndSwapslotTrailing icon/action. Governed by slotEnd.
slotContentSwapslotBody content (default 32px height). Governed by slotContent.
📝Slot booleans and their swaps are coupled — always set both. A slot left true with no swap leaves a visible gap; false collapses it (≈ display:none).

Variants

8 variants = breakpoint (xs / md) × state (default / active) × heightFill (false / true). Default combination: slotStart=true, hasStatusIndicator=true, heightFill=false, all other optionals off.

States

  • default — root fill white (bg-secondary #FFFFFF).
  • active — root fill light grey #EDEDED, signalling selection / focus. No child nodes recolour.
  • Focus — focus ring via shadow-focus (4px #3E5FFF outer + 2px #FFFFFF spacer).
⚠️Drive selection via the state prop only — never override the fill directly on an instance (bypasses variant logic and breaks theme tokens).

Sizes

Driven by breakpoint only — there is no separate size axis. xs = 382px (mobile-first compact); md = 395px (more internal padding, slightly larger type). Both share an identical layer tree; intrinsic width differs by just 13px.

💡Prefer container-based sizing (width: 100%) and use breakpoint to convey responsive intent rather than hard-coding pixel widths.

Breakpoints

Card defines only two breakpoints — xs and md. There is no sm, lg or xl. heightFill (false/true) is the orthogonal axis used to make cards stretch for equal-height rows.

Design tokens

Layout · surface · elevation

  • Radius: border-radius-lg = 20.
  • Padding / gap: 16 (container padding & vertical stack gap).
  • Background (default): bg-secondary = #FFFFFF. Active: literal #EDEDED (applied by the variant; not a named token).
  • Shadow: shadow-bevel — drop #0000000a 0/2/8 + inner #ffffff00 0/0.5.
  • Focus ring: shadow-focus — #3E5FFF spread 4 + #FFFFFF spread 2.
  • Status dot: green-400 #37c871 / border-success #37c871, 16×16.

Typography (Inter)

  • Tagline: caption — Regular 12/18, text-secondary #696a6d.
  • Heading: body-sm-medium — Medium 14/20, text-primary #2a2a2d.
  • Subheading: text-secondary #696a6d. Heading & subHeading are recolourable (e.g. subHeading = text-critical).

Accessibility

  • Give every Card a descriptive accessible label conveying its destination/action — not generic text.
  • If the Card contains interactive children (buttons/links), each must be independently keyboard accessible.
  • Mark decorative slotStart icons with an empty accessibility label to avoid redundant announcements.
  • Communicate the active state to screen readers via aria-pressed / aria-selected as appropriate.

Usage

✓ Do

  • Use a descriptive heading + concise subheading to orient at a glance.
  • Use heightFill=true in grid rows for consistent card heights.
  • Turn off hasStatusIndicator for archived/completed/offline cards.

✕ Don't

  • Don’t fill cards with lengthy prose — keep content scannable.
  • Don’t nest Cards within Cards.
  • Don’t use a Card for purely static, non-interactive content.

Implementation status

No native implementation of this content Card exists yet — fresh build per platform. (The pre-existing generic CardContainer control is a different component.)

Android iOS macOS Windows

Changelog

  • v1.030.6.2026
    • Initial release.
  • v0.918.6.2026
    • Initial draft — added new Card component with predefined content.

Ticket scaffold

Title: Card v1.0 — build clickable content card [PLATFORM]

Acceptance criteria

  • Text stack: tagline / heading / subheading with the specified type tokens.
  • Props: breakpoint, state, heightFill, slotStart, slotContent, slotEnd, hasBadge, hasStatusIndicator (+ matching swaps).
  • Slot booleans collapse cleanly when off (no residual gap); badge is overlay-positioned (no layout shift).
  • state=active changes only the root fill (#FFFFFF → #EDEDED); focus ring via shadow-focus.
  • heightFill=true stretches to container height; default sizes to content.
  • Whole card is one focusable, labelled, activatable control; selection announced to AT.
  • Light + dark verified; visual diff against the Figma Developer Handover frame.

Jira ticket template

Jira wiki-markup. Copy into a new issue, replace every [PLACEHOLDER], and duplicate one per platform.

Jira · duplicate per platform
h2. [PLATFORM] · Card v1.0 — build clickable content card

*Project / Epic*  : [EPIC-KEY]  Aurora AppKit · Supernova
*Issue type*      : Story
*Components*      : Card · [PLATFORM]
*Labels*          : aurora-appkit, supernova, design-system, card
*Priority*        : [Medium]
*Story points*    : [estimate]
*Fix version*     : Card v1.0
*Sprint*          : [sprint]
*Assignee*        : [assignee]

h3. Background
New clickable content card for lists/grids (tagline / heading / subheading + status dot + badge + swap slots). NOTE: distinct from the existing generic {{CardContainer}} control — this is a new, higher-level component.

h3. Objective
Build Card v1.0 on [PLATFORM]: the content card with its slots, states and breakpoints, mapped to [PLATFORM] conventions.

h3. Design source
* Figma — "Aurora AppKit · Components" -> Card page (Specification, Developer Handover, Changelog frames)
* Handover spec — supernova-handover/card.html
* [paste the platform-specific Figma frame link]

h3. Spec (platform-agnostic — map to [PLATFORM] idioms)
* Properties : {{breakpoint}} (xs 382 / md 395) · {{state}} (default | active) · {{heightFill}} (false | true) · {{slotStart}} (default true) · {{slotContent}} (default false) · {{slotEnd}} (default false) · {{hasBadge}} (default false) · {{hasStatusIndicator}} (default true) · swaps {{slotStartSwap}} / {{slotContentSwap}} / {{slotEndSwap}}
* Text stack : tagline {{caption}} · heading {{body-sm-medium}} · subheading {{text-secondary}}
* Surface : {{bg-secondary}} #FFFFFF (default) -> #EDEDED (active) · radius {{border-radius-lg}} 20 · padding/gap 16 · {{shadow-bevel}} · focus ring {{shadow-focus}}
* Status dot : 16x16, {{green-400}} / {{border-success}}
* Slot booleans and their swaps are coupled — off collapses cleanly (no residual gap); badge is overlay-positioned (no layout shift)

h3. Scope
In scope : the content Card on [PLATFORM] at xs / md with all props.
Out of scope : the existing {{CardContainer}}; other platforms.

h3. Dependencies
* StatusIndicator and Badge components on [PLATFORM]

h3. Acceptance criteria
# Renders the text stack with the specified type tokens; all eight props behave per spec.
# {{state = active}} changes only the root fill (#FFFFFF -> #EDEDED); focus shows {{shadow-focus}}.
# {{heightFill = true}} stretches to container height; default sizes to content.
# Slot booleans collapse with no residual gap; {{hasBadge}} overlay causes no layout shift.
# The whole card is one focusable, labelled, activatable control; selection announced via the platform "selected/pressed" semantics.
# Tokens only; light and dark verified.

h3. Definition of Done
* Matches the Figma Developer Handover (visual diff) at xs / md, light and dark
* Tokens only (the #EDEDED active fill is the documented exception if no token exists)
* Tests updated; reviewed and merged; version v1.0; changelog updated

h3. QA / test notes
* Toggle every slot/flag; verify gap collapse and badge overlay
* Keyboard activation + selection announcement
Source: Figma “Aurora AppKit – Components” · Card page · Specification, Developer Handover & Changelog frames. Styled with the Aurora vibe package. Compiled 30.6.2026.