Action-list row with a primary label and a secondary description line beneath it.
Merge into base List via a <code>description</code> slot
This component duplicates the entire base List anatomy just to render a 12/14 description line under the label. Native platforms already expose this as one parameter — SwiftUI composes primary + secondary labels in a
VStack, Material 3's ListItem has supportingContent. Collapse all three siblings (List, with Description, with Counter) into one Action List component with optional description and trailing slots. This also closes the Density-coverage gap (base List has Compact + Expanded; this variant does not).In Context
Contexts are illustrative. Description rows appear in settings lists, notification preferences, and profile menus where each row needs a subtitle explaining the action.
Live Preview
Label
description
CTA
Properties
state
icon
trailingComponent
chevron
bottomBorder
DS Health
Reusable
Warn
Works for any settings or notification list row with a subtitle. Duplicates base List's anatomy instead of reusing it — a
description slot on the base component would handle this.Self-contained
Pass
Carries its own text styles (
Primary/Label/Light/Base + Primary/Multi-line Label/Light/Fine), background, and spacing.Consistent
Warn
Ships only 3 states vs base List's 6 (missing Density axis). Leading asset is a raw
#c2c6cf circle placeholder, not an instance of List Item Asset. C5 C1Composable
Fail
Exists as a standalone sibling of base List rather than a compositional variant — bloats the library and forces consumers to swap entire components just to add a subtitle. C4
Behavior
| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default | N/A | N/A | state=Default | Label #0A2757, description #6780A9 |
| Disabled | No | N/A | state=Disabled | Label + description both recolor to #c2cfe5, CTA to #9bc5fd |
| Loading | N/A | N/A | state=Loading | Two shimmer lines replace text; trailing icon becomes a 53px shimmer block |
| Pressed | No | No | — | Missing — native pressed token should map to main/action-list/color/pressed/bg (to be added) C5 |
Open Issues
- Sibling component duplicates base List anatomy. A 12/14 description line is a single optional parameter on every native list primitive (SwiftUI secondary label, Material
supportingContent). Standalone sibling forces consumers to swap whole components instead of flipping one prop. C4 · Native Mappability - Leading asset is a raw
#c2c6cfplaceholder. The icon container is a 32px filled circle with a hard-coded gray — not an instance of List Item Asset, not bound to a token. Consumers can override via instance-swap but the default is visually broken. C1 · Layer Structure & Naming - Missing Density axis. Base List ships
Density=Compact(48px) andDensity=Expanded(56px). This variant skips the axis entirely, producing a 70–76px row with no Compact counterpart. C2 · Variant & Property Naming - No Pressed state. Only Default / Disabled / Loading are modeled. Action lists are tappable — pressed styling should live in Figma as a token so native
.pressed/ripplecan reference it. C5 · Interaction State Coverage - Code Connect mappings not registered. Blocked until family consolidation lands — no point mapping a component that will be removed. C7 · Code Connect Linkability
Design Recommendations
- Consolidate into one
Action Rowcomponent. This file becomes asubtitle: String?configuration of the unifiedAction Row, alongside the "with Counter" sibling mapped totrailing=counter. Three components collapse into one with clean slot-based composition. Family - Replace the leading-icon placeholder with a Figma Slot. The raw 32px
#c2c6cfcircle should become a namedleadingslot accepting any List Item Asset instance or a 32 × 32 icon. Maps 1:1 to SwiftUI@ViewBuilder leading/ ComposeleadingContent. Slot - Add Density × Pressed coverage to the merged component. The consolidated Action List should carry Compact (48px) + Expanded (56px) from base List, plus a Pressed visual state so tokens like
main/action-list/color/pressed/bgexist for native ripple/highlight. State - Rename the family to
Action Row. "Action List" implies a collection; each component here is a single row. Native name:EBActionRow. Tokens can stay undermain/action-list/...or be renamed tomain/action-row/...for consistency. Rename
Variants
State=Default
DES DEV
Active row. Leading icon + label + description + optional CTA + chevron.
Label
Description
Properties
State
Properties
Variant State=Default
State Default
Colors
Bg #FFFFFF
Label #0A2757
Description #6780A9
Link #005CE5
Chevron #005CE5
Layout
Row height 60px
Padding H 12px
Padding V 12px
Chevron size 24 × 24
Hit target full row
Typography
Label style Primary/Label/Light/Base
Label font Proxima Soft Semibold · 16 / 16 · +0.25
Description style Primary/Multi-line Label/Light/Fine
Description font Proxima Soft Semibold · 12 / 14 · +0.5
Colors by State
| Role | Token | Default | Disabled | Loading |
|---|---|---|---|---|
| Row bg | main/action-list/color/{state}/bg | #FFFFFF | #FFFFFF | #FFFFFF |
| Label | main/action-list/color/{state}/label | #0A2757 | #C2CFE5 | – |
| Description | main/action-list/color/{state}/description | #6780A9 | #C2CFE5 | – |
| CTA label | main/action-list/color/default/label-link | #005CE5 | #9BC5FD | – |
| Chevron | main/action-list/color/{state}/chevron | #005CE5 | #9BC5FD | – |
| Skeleton line / block | bg/color-bg-strong | – | – | #EEF2F9 |
| Leading placeholder | — | #C2C6CF | #C2C6CF | – |
State=Disabled
DES DEV
Non-interactive. Label + description recolor to <code>#c2cfe5</code>; CTA + chevron use <code>#9bc5fd</code>.
Label
Description
Properties
State
Properties
Variant State=Disabled
State Disabled
Colors
Bg #FFFFFF
Label #C2CFE5
Description #C2CFE5
Link #9BC5FD
Chevron #9BC5FD
Layout
Row height 60px
Padding H 12px
Padding V 12px
Chevron size 24 × 24
Hit target full row
Typography
Label style Primary/Label/Light/Base
Label font Proxima Soft Semibold · 16 / 16 · +0.25
Description style Primary/Multi-line Label/Light/Fine
Description font Proxima Soft Semibold · 12 / 14 · +0.5
Layout
| Role | Token | Value |
|---|---|---|
| Row width | — | 360px (fixed) |
| Row height | — | 60px (hug, 2 text lines + 6px gap) |
| Outer padding (Default / Disabled) | space/space-12 | 12px all sides |
| Loading padding | space/space-12, space/space-24 | 14px vertical · 12px left · 24px right |
| Icon → text gap | space/space-12 | 12px |
| Label → description gap | space/space-6 | 6px |
| Leading icon size | — | 32 × 32 |
| Chevron wrapper padding | space/space-4 | 4px top/bottom · 4px left/right |
| Chevron icon size | — | 24 × 24 |
| Corner radius | radius/radius-0 | 0 (square) |
State=Loading
DES DEV
Skeleton. Two shimmer lines replace text; trailing is a 53px shimmer block.
Properties
State
Properties
Variant State=Loading
State Loading
Colors
Bg #FFFFFF
Skeleton #EEF2F9
Layout
Row height 60px
Padding H 12px
Padding V 14px
Chevron size 24 × 24
Hit target full row
Typography
Label style Primary/Label/Light/Base
Label font Proxima Soft Semibold · 16 / 16 · +0.25
Typography
| Role | Token | Spec |
|---|---|---|
| Label | Primary/Label/Light/Base | Proxima Soft Semibold · 16 / 16 · tracking 0.25 |
| Description | Primary/Multi-line Label/Light/Fine | Proxima Soft Semibold · 12 / 14 · tracking 0.5 |
| CTA | Primary/Label/Light/Base | Proxima Soft Semibold · 16 / 16 · tracking 0.25 |
Installation
Planned API
iOS — Swift Package Manager
// In Xcode: File → Add Package Dependencies "https://github.com/AY-Org/eb-ds-ios"
Android — Gradle (Kotlin DSL)
dependencies { implementation("com.eastblue.ds:list:1.0.0") }
Property Mapping
| Figma Property | SwiftUI | Compose |
|---|---|---|
| label | title: String | title: String |
| description? | subtitle: String? | supportingContent: String? |
| icon (Slot) | @ViewBuilder leading | leadingContent: @Composable () -> Unit |
| trailingComponent (Slot) | @ViewBuilder trailing | trailingContent: @Composable () -> Unit |
| chevron | showChevron: Bool | showChevron: Boolean |
| bottomBorder | showDivider: Bool | showDivider: Boolean |
| state | .disabled(true), loading modifier | enabled = false, loading param |
SwiftUI
ios/Components/List/EBActionList.swift
Jetpack Compose
android/components/list/EBActionList.kt
Usage Snippets Planned API
Usage
// With description + CTA + chevron EBActionList( title: "Notifications", subtitle: "Receive alerts for new transactions", leading: { EBListItemAsset(.icon("bell")) }, trailing: { Text("Edit").foregroundStyle(.blue) }, showChevron: true ) // Disabled EBActionList(title: "Premium", subtitle: "Unlock higher limits") .disabled(true) // Loading EBActionList(title: "", subtitle: "") .redacted(reason: .placeholder)
// With description + CTA + chevron EBActionList( title = "Notifications", supportingContent = "Receive alerts for new transactions", leadingContent = { EBListItemAsset(Icon.Bell) }, trailingContent = { Text("Edit", color = Color.Blue) }, showChevron = true ) // Disabled EBActionList( title = "Premium", supportingContent = "Unlock higher limits", enabled = false ) // Loading EBActionList(title = "", loading = true)
Accessibility
| Requirement | iOS | Android |
|---|---|---|
| Touch target | Row is tappable via Button wrapper or .onTapGesture; min 44pt | Modifier.clickable(...); min 48dp |
| Combined label | .accessibilityElement(children: .combine) so VoiceOver reads "Label, description, button" | Modifier.semantics(mergeDescendants = true) { role = Role.Button } |
| Disabled state | .disabled(true) — VoiceOver announces "dimmed" | enabled = false — TalkBack announces "disabled" |
| Loading state | .accessibilityLabel("Loading") on skeleton rows | Modifier.semantics { contentDescription = "Loading" } |
| Chevron semantics | Decorative — .accessibilityHidden(true) | contentDescription = null |
Criteria Scorecard
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Requires Rework | Leading asset is a raw #c2c6cf circle placeholder, not a List Item Asset instance or a Figma Slot. |
| C2 | Variant & Property Naming | Needs Refinement | Property names are clean (state, icon, chevron, description) but the Density axis from base List is missing. |
| C3 | Token Coverage | Ready | All label, description, CTA, chevron, bg colors bound to main/action-list/.... Spacing uses space/*. |
| C4 | Native Mappability | Requires Rework | Sibling component for what natives handle as a single parameter. Consolidate with base List. |
| C5 | Interaction State Coverage | Needs Refinement | Default / Disabled / Loading only — no Pressed. Action lists are tappable; pressed token needed. |
| C6 | Asset & Icon Quality | Ready | Chevron is a vector instance. Leading placeholder is decorative, user-provided via instance swap. |
| C7 | Code Connect Linkability | Not Mapped | Blocked — consolidate family first, then map once. |
Variants Inventory (3 total)
| State | Width × Height | Padding | Notes | Node ID |
|---|---|---|---|---|
| Default | 360 × 60 | 12 all sides | Label + description + CTA + chevron | 18577:14605 |
| Disabled | 360 × 60 | 12 all sides | Label + description recolored; CTA + chevron dimmed | 18577:14617 |
| Loading | 360 × 60 | 14 V · 12 L · 24 R | Two shimmer lines + 53px trailing shimmer block | 18577:14629 |
1.0.0 — April 2026Major
Initial Assessment · node 18577:14604
Component assessed — 3 variants (Default / Disabled / Loading). Sibling of base List + List with Counter. Documented
InitialLeading placeholder hardcoded — 32px circle fill
C1 Open#c2c6cf, not an instance of List Item Asset. OpenMissing Density axis — Base List ships Compact + Expanded; this sibling ships neither. Open
C2 OpenSibling duplicates base List — Description is a single optional parameter on every native list primitive; collapse into one Action List with
C4 Opendescription slot. OpenNo Pressed state — Action list is tappable; pressed token should exist. Open
C5 OpenCode Connect mappings — Not registered; blocked until family consolidation. Open
C7 Open