East Blue
KeepNeeds Refinement
Generic Card Component link

A tappable content card — slotted leading icon, a heading with tag and badge, two label-and-description rows, and a slotted trailing chevron.

Keep — all findings resolved
Rebuilt on node 5412:31504 in the 2026 Working File as Status = Default | Skeleton × State = Default | Disabled × IconSize = XL | LG | MD | SM | XS | XXS over 18 variants. The naming pass is complete: all three properties PascalCase per §1 with Title Case values per §5, the ⤷ glyph and the # sigil both gone, text layers on the §3 vocabulary and §7 hierarchy, frames PascalCase with the two meaningless offset frames replaced by PreambleContainer and IconContainer, and both slots kebab-cased with the -Slot suffix the rest of the system uses. Splitting Skeleton onto its own Status axis matches §6 and Upload File. The paired TextContainer rows are confirmed intentional peers, the state coverage is confirmed complete at 18 variants, and all six icon sizes are confirmed in use. All four DS Health traits pass; the only item still open is Code Connect, blocked until the native library exists.
In Context

Generic Card stacks vertically into a scrolling list — product catalogs, service menus, transaction history detail screens. Icon size tightens as the density of the list increases.

Live Preview
BlurbTag

Heading Goes Here

Label:Description goes here

Label:Description goes here

Label
Content
blurb
tag
heading
description
badge
Properties
iconSize
state
Slots
hasSubtitle
hasBlurb
hasTag
has2ndDesc
hasBadge
hasChevron
DS Health
Reusable
Pass
A generic tappable content card — the two slots and the label/description rows carry product, transaction or service content without the component knowing which.
Self-contained
Pass
Owns its container, spacing and typography, and composes shared Badge and Chevron Right instances rather than redrawing them.
Consistent
Pass
Status, State and IconSize are all PascalCase per §1 with Title Case values per §5 on the standard sizing vocabulary; Skeleton sits on Status rather than competing with interaction on State, per §6; text layers follow the §3 vocabulary and the §7 hierarchy; frames are PascalCase throughout, including the skeleton variants; and both slots are kebab-cased with the -Slot suffix used across the system.
Composable
Pass
leadingIcon and trailingIcon are both real Figma Slots, so the artwork and the trailing affordance are consumer-supplied, and the badges are shared instances.
Behavior
State iOS Android Figma Property Notes
Default Yes Yes state=Default Normal row — all content visible, chevron shown when hasChevron.
Skeleton (loading) Yes Yes state=skeleton Loading pattern — gray rounded placeholders where each content slot would render. Kudos for shipping this as a first-class variant.
Pressed N/A N/A Not built Tappable row (has chevron) — needs a pressed state with background tint for tap feedback.
Disabled N/A N/A Not built For temporarily-unavailable services (e.g. maintenance). Typically dimmed label + muted icon.
Issues
  • Leading icon is a real Figma Slot. v2.0: Rebuilt on node 5412:31504 in the 2026 Working File. leadingIcon is a genuine SLOT holding a Placeholder instance as its swap target, replacing the hardcoded circle the previous assessment flagged. A consumer supplies their own artwork without detaching, and native handoff has a real content slot to bind. (C1 · Slot) C1 · Layer Structure & Naming
  • Chevron is a vector instance in a slot. v2.0: The raster chevron is gone. trailingIcon is a SLOT carrying a Chevron Right instance from the shared icon library, so it recolours from tokens and stays crisp at any density — and because it is slotted, a card that needs a different trailing affordance can swap it. (C6 · Asset) C6 · Asset & Icon Quality
  • iconSize values moved from numeric to semantic. v2.0: The six numeric values are replaced by a t-shirt scale — xl | l | m | s | xs | xxs — which is the naming half of the previous recommendation. The count is unchanged at six, and whether all six earn their place is tracked separately below. (C2 · Rename) C2 · Variant & Property Naming
  • Disabled state added. v2.0: state=disabled ships across all six icon sizes, closing half of the missing-states finding. Pressed is still absent and is tracked below. (C5) C5 · Interaction State Coverage
  • skeleton moved onto its own Status axis. v2.1: The schema is now Status = Default | Skeleton × State = Default | Disabled × iconSize, matching the §6 rule and the shape Upload File uses. A skeleton is the system reporting that content has not arrived; disabled is how the user may interact with it. Separating them means the two no longer compete for one axis. (C2 · Property) C2 · Variant & Property Naming
  • State and Status PascalCase, all values Title Case. v2.1: Default, Disabled, Skeleton per §5, and the icon scale is now XL | LG | MD | SM | XS | XXS — aligned to the standard sizing vocabulary rather than the single-letter l | m | s it used before. (C2 · Rename) C2 · Variant & Property Naming
  • The ⤷ glyph is gone and slots are kebab-cased. v2.1: ⤷ icon, ⤷ leadingIcon and ⤷ trailingIcon are now MediaContainer, Leading-Icon and Trailing-Icon — the literal arrow character is removed from every layer, and both slots follow §4 kebab-case, so nothing in the tree blocks a generated identifier. (C1 · Rename) C1 · Layer Structure & Naming
  • Legacy sigil dropped and frames moved to PascalCase. v2.1: #tag → Preamble, #name → Title, #label → Label, #description → Description, putting the text layers on the §3 vocabulary and the §7 hierarchy. The frames follow: container → ContentRow, content-block → ContentBlock, text-container → TextContainer, badge-container → BadgeContainer. Both frames named offset are gone, replaced by PreambleContainer and IconContainer, which say what they hold. (C1 · Rename) C1 · Layer Structure & Naming
  • Skeleton variants brought onto the shared vocabulary. v2.1: icon-container — with its trailing space — is now MediaContainer, content-block is ContentBlock, and the offset frame standing in for the chevron is IconContainer, all matching the names their default siblings use. A reviewer no longer needs a second mental model to read a skeleton variant. (C1 · Rename) C1 · Layer Structure & Naming
  • Two TextContainer rows confirmed intentional peers. v2.2: The Coverage block holds two identically-structured rows by design — each a Label and Description pair, the second carrying a further line item rather than a different kind of content. Sharing a name is correct here: they are peers, not a primary and a secondary, and naming them apart would imply a hierarchy the card does not have. Note for implementation: identically-named siblings are matched by order when Figma swaps variants, so an iconSize change re-matches the two rows positionally. That is reliable while both rows are present and in order, and it is the reason to keep them as a fixed pair rather than making either one optional. Native implementations should model this as a list of two label-value rows rather than as two named properties. (C1 · Docs) C1 · Layer Structure & Naming
  • State coverage confirmed as-is. v2.2: State = Default | Disabled is the intended coverage — no pressed state, and Status=Skeleton deliberately ships only with State=Default. A skeleton is a placeholder for content that has not arrived, so it cannot meaningfully be disabled, and the 18 built variants are therefore the complete set rather than 18 of a nominal 24. Native implementations should treat Skeleton × Disabled as unreachable and should not expect a pressed treatment from the component. (C5) C5 · Interaction State Coverage
  • iconSize → IconSize. v2.3: Verified on the live node — all 18 variants read Status × State × IconSize. Every property in the set is now PascalCase per §1 with Title Case values per §5, closing the property pass. (C2 · Rename) C2 · Variant & Property Naming
  • Slot suffix aligned to the family convention. v2.3: Leading-Icon and Trailing-Icon are now Leading-Icon-Slot and Trailing-Icon-Slot — kebab-case per §4 with the -Slot suffix the rest of the system uses on Bottom Sheet, Service Item and Upload File. A consumer can now tell a slot from a frame by its name alone, across every component. (C1 · Rename) C1 · Layer Structure & Naming
  • All six icon sizes confirmed in use. v2.3: XL | LG | MD | SM | XS | XXS stays at six by owner confirmation — each size appears in a real screen rather than being carried forward from the retired numeric scale. The 18-variant count is therefore the intended size of the set, not an artefact. (C2 · Property) C2 · Variant & Property Naming
Variants
Default
BlurbTag

Heading Goes Here

Label:Description goes here

Label:Description goes here

Label
Properties
State
IconSize
Properties
Status Default
State Default
IconSize XL
Colors
Background #FFFFFF
Border #E5EBF4
Preamble #005CE5
Tag #D61B2C
Title #0A2757
Label #90A8D0
Description #445C85
Badge background #E5F1FF
Badge label #005CE5
Leading icon placeholder #D7E0EF
Chevron #005CE5
Typography
Title Primary/Headlines/Block
Preamble Primary/Label/Small
Label Secondary/Bold/Caption
Description Secondary/Bold/Caption
Layout
Height 148
Width 360
Radius 0
Padding H —
Padding V —
Gap —
Border 1 · bottom
Alignment —
Colors by Status
Role Element Token Value
Default Background — #FFFFFF
Default Border — #E5EBF4
Default Preamble — #005CE5
Default Tag — #D61B2C
Default Title — #0A2757
Default Label — #90A8D0
Default Description — #445C85
Default Badge background — #E5F1FF
Default Badge label — #005CE5
Default Leading icon placeholder — #D7E0EF
Default Chevron — #005CE5
Default · Disabled Preamble — #9BC5FD
Default · Disabled Title — #C2CFE5
Default · Disabled Label — #C2CFE5
Default · Disabled Description — #C2CFE5
Default · Disabled Badge background — #C2C6CF
Default · Disabled Badge label — #FFFFFF
Default · Disabled Leading icon placeholder — #9BC5FD
Default · Disabled Chevron — #9BC5FD
Skeleton Background — #FFFFFF
Skeleton Placeholder bars — #EEF2F9
Skeleton Leading icon placeholder — #EEF2F9
Skeleton
Properties
IconSize
Properties
Status Skeleton
State Default
IconSize XL
Colors
Background #FFFFFF
Placeholder bars #EEF2F9
Leading icon placeholder #EEF2F9
Typography
Text layers None
Layout
Height 146
Width 360
Radius 0
Padding H —
Padding V —
Gap —
Alignment —
Installation Planned API

iOS — Swift Package Manager

.package(url: "https://github.com/AY-Org/eb-ds-ios", from: "1.0.0")

Android — Gradle (Kotlin DSL)

implementation("com.eastblue.ds:card:1.0.0")

Import

import EastBlueDS
import com.eastblue.ds.card.*
Property Mapping

Status, State and IconSize are the set’s three variant properties. Leading-Icon-Slot, Trailing-Icon-Slot and Description are Figma Slots. Preamble and Title are text layers; Tag and Badge are nested Badge instances — all read from the layer tree of 5412:31505. Whether the text layers are exposed on the property panel is not readable with the plugin.

Figma PropertySwiftUICompose
Status — Default, Skeleton isLoading: true isLoading = true
State — Default, Disabled .disabled(true) enabled = false
IconSize — XL, LG, MD, SM, XS, XXS .ebIconSize(.xl / .lg / .md / .sm / .xs / .xxs) iconSize = EBIconSize.XL / LG / MD / SM / XS / XXS
Leading-Icon-Slot (slot) .ebLeadingIcon(Image) leadingIcon = { Icon(…) }
Trailing-Icon-Slot (slot) .ebTrailingIcon(Image) — Chevron Right by default trailingIcon = { Icon(…) } — Chevron Right by default
Description (slot) .ebDescription(label: "Label", "…") once per row descriptions = listOf("Label" to "…")
Preamble (text) .ebPreamble("Blurb", tag:) preamble = "…"
Title (text) EBGenericCard("Heading Goes Here") title = "…"
Tag (nested Badge instance) .ebPreamble(_, tag: "Tag") tag = "…"
Badge (nested Badge instance) .ebBadge("Label") badge = "…"
Usage Snippets Planned API
Default
EBGenericCard("Heading Goes Here")
    .ebPreamble("Blurb", tag: "Tag")
    .ebDescription(label: "Label", "Description goes here")
    .ebDescription(label: "Label", "Description goes here")
    .ebBadge("Label")
    .ebLeadingIcon(Image(systemName: "star.fill"))
    .ebIconSize(.xl)
EBGenericCard(
    title = "Heading Goes Here",
    preamble = "Blurb",
    tag = "Tag",
    descriptions = listOf("Label" to "Description goes here", "Label" to "Description goes here"),
    badge = "Label",
    leadingIcon = { Icon(Icons.Filled.Star, null) },
    iconSize = EBIconSize.XL
)
Skeleton
EBGenericCard(isLoading: true)
    .ebIconSize(.xl)
EBGenericCard(
    isLoading = true,
    iconSize = EBIconSize.XL
)
Accessibility
RequirementiOSAndroid
Row as a button Whole row in Button; one accessibilityLabel combining preamble, tag, title, descriptions and badge. Modifier.clickable { onTap() }.semantics(mergeDescendants = true) on the row.
Reading order Preamble, tag, title, each label and description pair, then badge — top to bottom as drawn. Same order; TalkBack follows the composition order.
Disabled .disabled(true) adds the .notEnabled trait. enabled = false sets the disabled semantics.
Loading Announce "Loading" once; .accessibilityHidden(true) on the placeholder bars. contentDescription = "Loading" on the skeleton container; placeholders cleared with clearAndSetSemantics.
Dynamic type Title 18 pt and the 12 pt rows scale with Dynamic Type; the row grows in height. Text in sp; the row grows with the font scale.
Minimum target 148 pt row ≥ 44 pt. 148 dp row ≥ 48 dp.
Usage Guidelines

Do

Pick IconSize by list density — XL for a product catalog, XXS for a dense service menu.

Don't

Don’t mix icon sizes inside one list.

Do

Keep the Title to one line inside the 180 px content block.

Don't

Don’t let the title wrap under the tag — shorten it instead.

Do

Swap Leading-Icon-Slot for the product or service icon at 1:1.

Don't

Don’t ship the Placeholder instance to production.

Do

Use Status Skeleton while the list loads.

Don't

Don’t pair Skeleton with Disabled — the set does not build it.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Needs Refinement PascalCase frames and three named slots on 5412:31505. A _space_40 spacer instance sits between ContentBlock and IconContainer — confirm it or replace it with padding.
C2 Variant & Property Naming Ready Status, State and IconSize with Title Case values; no absence-based names.
C3 Token Coverage Ready Title resolves to Primary/Headlines/Block, Preamble to Primary/Label/Small, Label and Description to Secondary/Bold/Caption. Colour variable bindings are not readable with the plugin — confirm in Dev Mode.
C4 Native Mappability Ready Three enums, three slots, two text values and two Badge instances — maps 1:1 onto EBGenericCard.
C5 Interaction State Coverage Ready Default and Disabled confirmed as the intended coverage (v2.2); Skeleton exists at State Default only.
C6 Asset & Icon Quality Ready Chevron Right is a vector instance in Trailing-Icon-Slot; Leading-Icon-Slot holds a swappable Placeholder instance; Tag and Badge are Badge instances.
Variants Inventory (18 total)

2 Status × 2 State × 6 IconSize, Skeleton without Disabled = 18 variants

IconSizeVariantsCount
XLDefault · Disabled · Skeleton3
LGDefault · Disabled · Skeleton3
MDDefault · Disabled · Skeleton3
SMDefault · Disabled · Skeleton3
XSDefault · Disabled · Skeleton3
XXSDefault · Disabled · Skeleton3
View full IconSize × Status × State breakdown (18 rows)
IconSizeStatusStateNodeDimensions
XLDefaultDefault5412:31505360 × 148
XLDefaultDisabled5418:32487360 × 148
XLSkeletonDefault5412:31530360 × 146
LGDefaultDefault5412:31541360 × 148
LGDefaultDisabled5418:32462360 × 148
LGSkeletonDefault5412:31566360 × 146
MDDefaultDefault5412:31577360 × 148
MDDefaultDisabled5418:32437360 × 148
MDSkeletonDefault5412:31602360 × 146
SMDefaultDefault5412:31613360 × 148
SMDefaultDisabled5418:32412360 × 148
SMSkeletonDefault5412:31638360 × 146
XSDefaultDefault5412:31649360 × 148
XSDefaultDisabled5418:32387360 × 148
XSSkeletonDefault5412:31674360 × 146
XXSDefaultDefault5412:31685360 × 148
XXSDefaultDisabled5418:32362360 × 148
XXSSkeletonDefault5412:31710360 × 146
1.0.2 — September 2026Patch
Style and Code tabs re-read · node 5412:31504
Style tab rebuilt from the 18 live variants. Cards follow Status — Default, Skeleton — with State and IconSize as panel controls; colours, text styles and the 148 / 146 heights read off 5412:31505 and 5412:31530. Padding, gap, alignment and colour tokens are not readable with the plugin and stay —.
Docs
Code tab regrouped on the Status × State × IconSize schema. Property Mapping is one row per property with the three slots, Usage Snippets and Guidelines added, Scorecard regraded, Variants Inventory moved from the 12 numeric iconSize nodes to the 18 live nodes with a summary and full breakdown.
Docs
A spacer instance sits in the layer tree. _space_40 (an instance carrying a Roboto "40" label) separates ContentBlock from IconContainer on 5412:31505. Confirm it is intentional or replace it with auto-layout padding. Filed from the scorecard for the Component Review.
C1
1.0.1 — September 2026Patch
Documentation backfill · node 5412:31504
Resolved issues recorded. 14 resolved issues on the Overview tab had no changelog row: Leading icon is a real Figma Slot; Chevron is a vector instance in a slot; iconSize values moved from numeric to semantic; Disabled state added; skeleton moved onto its own Status axis; State and Status PascalCase, all values Title Case; The ⤷ glyph is gone and slots are kebab-cased; Legacy sigil dropped and frames moved to PascalCase; Skeleton variants brought onto the shared vocabulary; Two TextContainer rows confirmed intentional peers; State coverage confirmed as-is; iconSize → IconSize; Slot suffix aligned to the family convention; All six icon sizes confirmed in use.
Docs
1.0.0 — April 2026Major
Initial Assessment · node 18482:35806
Verdict: Fix — Collapse iconSize to semantic scale, swap icon placeholder for a slot, vectorize the chevron, add pressed state. Open
Schema
Skeleton pattern acknowledged — First-class loading variant is rare and valuable. Adopt this pattern across the card/row family. Noted
Praise
C2 — iconSize collapse — 6 numeric values → 4 semantic sizes (xl/l/m/s). Open
C2
C6 — Icon slot + vector chevron — Adopt Figma Slot for leading media; vectorize chevron. Open
C6
C5 — Pressed / disabled — Tappable row needs both. Open
C5
C7 — Code Connect — Blocked on above. Open
C7