ConsolidateRequires Rework
Action List - with Counter Component link

Action-list row with a 32px leading icon, label, trailing chevron, and a trailing Counter pill.

Consolidate — fold into base Action List as a trailing slot
This variant sibling just adds an EBCounter to the base transaction row. That should be a trailing slot (or a counter: Int? parameter that swaps in a Counter) on the base component — not a second component with a duplicated 2 × 3 density/state matrix. Shipping as a sibling doubles maintenance cost on every token or layout change, and the same anti-pattern will repeat for the "with Description" sibling.
In Context

Used where a row needs to surface a pending count alongside the action — inbox folders, notification categories, or settings entries with outstanding items.

Inbox Notifications 5 Promos 2 Archive 0
Live Preview
Notifications
5
Properties
Density
State
label
count
DS Health
Reusable
Warn
Reusable on its own — but the reuse path collides with the base Transaction row. Teams have to pick between two near-identical components instead of one with a trailing slot. C1
Self-contained
Pass
Carries its own tokens, typography, and the trailing Counter composition. Nothing external needed to render.
Consistent
Warn
Density is PascalCase; State is PascalCase here but state (lowercase) on Counter — inconsistent casing across the family. Loading skeleton is a generic strip instead of a trailing pill shape. C2
Composable
Fail
Composition happens at the wrong layer. The Counter is already a standalone component — "row with a trailing Counter" should be the consumer wiring two components together (or a trailing slot on the row), not a third component that hardcodes both. C1
Behavior
State iOS Android Figma Property Notes
Default Yes Yes State=Default Brand-blue label, brand-blue chevron, filled Counter pill (#072592 on #EEF2F9).
Disabled Yes Yes State=Disabled Muted label (#C2CFE5), muted chevron (#9BC5FD), empty Counter pill.
Loading Yes Yes State=Loading Avatar circle, long label skeleton, trailing 46 × 16 strip. The strip doesn't actually match the Counter pill shape — see open issue.
Pressed / Focused N/A N/A Not modeled No pressed / focused variants on the row. Inherited gap — same issue as base Transaction row.
Open Issues
  • Duplicated variant matrix. This sibling recreates the base row's 2 × 3 (Density × State) matrix just to bolt on a trailing Counter. Every future change to the base row (radius, padding, token rename) has to be mirrored here. Fold into the base row via a trailing slot or a counter: Int? parameter. C1 · Layer Structure & Naming
  • Property casing is inconsistent across the family. Density and State use PascalCase, while the composed Counter child uses lowercase state. Pick one (recommend lowercase) and apply across every List Item and Counter property. C2 · Variant & Property Naming
  • Loading skeleton doesn't match the trailing Counter shape. The 46 × 16 strip is the generic "trailing icon" skeleton used on the base row — it doesn't look like a 24 × 24 pill. Either shape the skeleton to match or drop the Counter entirely in Loading (and let the skeleton stand in). C4 · Native Mappability
  • No pressed / focused states. Action rows are interactive targets; they need pressed and focused visuals for native parity. Missing on the base row too — fix once at the base. C5 · Interaction State Coverage
  • Code Connect mappings not registered. Blocked until the consolidation lands — wiring this sibling directly would entrench the duplication. C7 · Code Connect Linkability
Design Recommendations
  • Consolidate into one Action Row component. This file becomes a trailing=counter configuration of the unified Action Row (with a counter: Int value prop), alongside the "with Description" sibling mapped to subtitle: String?. Three components collapse into one with clean slot-based composition. Family
  • Adopt a Figma Slot for the trailing area. With the slot, this file's 6 variants disappear; consumers drop an existing Counter instance (node 18482:71321) into the trailing slot of the base row. Maps cleanly to @ViewBuilder trailing (SwiftUI) / trailing: @Composable () -> Unit (Compose) for Code Connect. Slot
  • Normalize property casing. Rename Densitydensity and Statestate so the whole Transaction family (base, with Counter, with Description) matches the lowercase convention used on Counter and most of the DS. Rename
  • Shape the Loading skeleton or omit the trailing. If the base row's Loading skeleton stays, match the trailing skeleton to a 24 × 24 pill so consumers see the actual footprint. Easier path: drop the trailing skeleton and let the 46 × 16 strip stand in for all trailing content. State
  • Add pressed / focused states at the base row. Action rows are tappable; native parity requires pressed + focused visuals. Fix on the base Transaction row once, and every "with X" sibling (or slotted consumer) inherits it. State
  • Document the migration path. When the base row gets a trailing slot, deprecate this component and link consumers to the base row with Counter composition. Otherwise teams keep instancing the sibling and the duplication doesn't go away. Docs
Variants
Compact · Default — brand label + filled Counter
DES DEV

360 × 56. 32 px icon, brand-blue label, chevron, trailing 24 × 24 filled Counter pill.

Label
3
Properties
State
Density
Properties
Density Compact
State Default
Colors
Bg #FFFFFF
Label #005CE5
Counter #EEF2F9
Chevron #005CE5
Layout
Row height 56px
Padding H 12px
Padding V 11px
Corner radius 6px
Chevron size 24 × 24
Typography
Label style Primary/Label/Light/Large
Font Proxima Soft Bold
Size 18px / 20px
Tracking +0.25
Colors by State
Role Token DefaultDisabledLoading
Row bg main/action-list/color/default/bg #FFFFFF #FFFFFF #FFFFFF
Label main/action-list/color/default/label-brand #005CE5
Label (disabled) main/action-list/color/disabled/label #C2CFE5
Chevron main/action-list/color/default/chevron #005CE5 #9BC5FD
Counter bg main/counter/color/filled/bg #EEF2F9 #EEF2F9
Counter label (filled) main/counter/color/filled/label #072592
Counter label (empty) main/counter/color/empty/label #C2CFE5
Skeleton bar bg/color-bg-strong #EEF2F9
Row shadow Depth/D0 drop-shadow(0 1 3 0 #E8EEF2C9)
Expanded · Default — taller row variant
DES DEV

360 × 64. Same composition; 15 px vertical padding vs 11 px on Compact.

Label
3
Properties
State
Density
Properties
Density Expanded
State Default
Colors
Bg #FFFFFF
Label #005CE5
Counter #EEF2F9
Chevron #005CE5
Layout
Row height 64px
Padding H 12px
Padding V 15px
Corner radius 6px
Chevron size 24 × 24
Typography
Label style Primary/Label/Light/Large
Font Proxima Soft Bold
Size 18px / 20px
Tracking +0.25
Layout
Role Token Value
Row width 360px
Row height (Compact) 56px
Row height (Expanded) 64px
Row padding H space/space-12 12px
Row padding V (Compact) 11px
Row padding V (Expanded) 15px
Icon → label gap space/space-12 12px
Label → trailing gap space/space-16 16px
Icon size 32 × 32
Chevron size 32 × 32
Counter size 24 × 24 (min) · hugs digits
Counter pad H space/space-8 8px
Counter radius radius/radius-round pill (99999)
Row radius radius/radius-2 6px
Compact · Disabled — muted tokens
DES DEV

Muted label, muted chevron, empty Counter pill.

Label
3
Properties
State
Density
Properties
Density Compact
State Disabled
Colors
Bg #FFFFFF
Label #C2CFE5
Counter #E5EBF4
Chevron #9BC5FD
Layout
Row height 56px
Padding H 12px
Padding V 11px
Corner radius 6px
Chevron size 24 × 24
Typography
Label style Primary/Label/Light/Large
Font Proxima Soft Bold
Size 18px / 20px
Tracking +0.25
Typography
Role Token Spec
Label Primary/Label/Large Proxima Soft Bold · 18 / 18 · +0.25
Counter Primary/Label/Small Proxima Soft Bold · 14 / 14 · +0.25
Expanded · Disabled — taller muted variant
DES DEV

Expanded height + Disabled tokens.

Label
3
Properties
State
Density
Properties
Density Expanded
State Disabled
Colors
Bg #FFFFFF
Label #C2CFE5
Counter #E5EBF4
Chevron #9BC5FD
Layout
Row height 64px
Padding H 12px
Padding V 15px
Corner radius 6px
Chevron size 24 × 24
Typography
Label style Primary/Label/Light/Large
Font Proxima Soft Bold
Size 18px / 20px
Tracking +0.25
Compact · Loading — skeleton row
DES DEV

Avatar circle + label line + 46 × 16 trailing strip. Strip shape doesn't match the Counter pill.

Properties
State
Density
Properties
Density Compact
State Loading
Colors
Bg #FFFFFF
Skeleton #EEF2F9
Layout
Row height 56px
Padding H 12px
Padding V 11px
Corner radius 6px
Chevron size 24 × 24
Typography
Label style Primary/Label/Light/Large
Font Proxima Soft Bold
Size 18px / 20px
Tracking +0.25
Expanded · Loading — taller skeleton row
DES DEV

Same skeleton with 16 px padding.

Properties
State
Density
Properties
Density Expanded
State Loading
Colors
Bg #FFFFFF
Skeleton #EEF2F9
Layout
Row height 64px
Padding H 12px
Padding V 16px
Corner radius 6px
Chevron size 24 × 24
Typography
Label style Primary/Label/Light/Large
Font Proxima Soft Bold
Size 18px / 20px
Tracking +0.25
Installation Planned API

iOS — Swift Package Manager

// In Xcode: File → Add Package Dependencies
"https://github.com/AY-Org/eb-ds-ios"

import EBDesignSystem

Android — Gradle (Kotlin DSL)

dependencies {
    implementation("com.eastblue.ds:list:1.0.0")
}

import com.eastblue.ds.components.EBListItemTransaction
Property Mapping
Figma PropertySwiftUICompose
(separate component) trailing Slot on base row @ViewBuilder trailing
Density density (renamed) density: .compact | .expanded
State state (renamed) state: .default | .disabled | .loading
icon (bool) leading Slot @ViewBuilder leading
label label label: String
chevron (bool) chevron chevron: Bool = true
counter (bool) derived from trailing slot
SwiftUI
ios/Components/List/EBListItemTransaction.swift
Jetpack Compose
android/components/list/EBListItemTransaction.kt
Usage Snippets Planned API
Usage
// Default — Compact density, trailing Counter
EBListItemTransaction(label: "Notifications") {
    EBAvatar(initials: "N")
} trailing: {
    EBCounter(count: unreadCount)
}

// Expanded density
EBListItemTransaction(label: "Promos") {
    EBAvatar(initials: "P")
} trailing: {
    EBCounter(count: 2)
}
.density(.expanded)

// Disabled row — counter stays in empty state
EBListItemTransaction(label: "Archive") {
    EBAvatar(initials: "A")
} trailing: {
    EBCounter(count: 0)
}
.disabled(true)

// Loading — trailing slot omitted; skeleton fills
EBListItemTransaction.loading()
// Default — Compact density, trailing Counter
EBListItemTransaction(
    label = "Notifications",
    leading = { EBAvatar(initials = "N") },
    trailing = { EBCounter(count = unreadCount) }
)

// Expanded density
EBListItemTransaction(
    label = "Promos",
    density = EBListDensity.Expanded,
    leading = { EBAvatar(initials = "P") },
    trailing = { EBCounter(count = 2) }
)

// Disabled row
EBListItemTransaction(
    label = "Archive",
    enabled = false,
    leading = { EBAvatar(initials = "A") },
    trailing = { EBCounter(count = 0) }
)

// Loading — trailing slot omitted; skeleton fills
EBListItemTransaction(state = EBListState.Loading)
Accessibility
RequirementiOSAndroid
Row role Wrap in Button / NavigationLink for tappable semantics Apply Modifier.clickable(...) + Role.Button
Counter label Compose accessibility label: "Notifications, 5 unread" — don't let VoiceOver read the digit alone Merge into row: contentDescription = "Notifications, 5 unread"
Disabled .disabled(true) — drops from hit-testing + dims label/chevron/counter enabled = false on clickable modifier
Loading Announce "Loading"; hide skeleton children from a11y tree Modifier.semantics { liveRegion = Polite } + hide skeletons
Chevron Decorative — .accessibilityHidden(true) contentDescription = null
Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Requires Rework Sibling duplicates the base Transaction row matrix. Consolidate via trailing slot.
C2 Variant & Property Naming Needs Refinement Density/State PascalCase mismatches lowercase Counter and most of DS.
C3 Token Coverage Ready All colors + spacing bound. Uses main/action-list/* + main/counter/*.
C4 Native Mappability Needs Refinement HStack/Row maps cleanly. Loading skeleton's 46 × 16 trailing strip doesn't match a Counter pill.
C5 Interaction State Coverage Needs Refinement No pressed / focused variants — inherited from base row.
C6 Asset & Icon Quality Ready Chevron is a vector instance; icon is a swap placeholder — same pattern as other List Items.
C7 Code Connect Linkability Not Mapped Do not wire this sibling — map the base row with trailing slot after consolidation.
Variants Inventory (6 total)

Density (2) × State (3) = 6 variants. Identical matrix to the base Transaction row.

#DensityStateNode IDDimensions
1CompactDefault18577:14638360 × 56
2ExpandedDefault18577:14647360 × 64
3CompactDisabled18577:14656360 × 56
4ExpandedDisabled18577:14665360 × 64
5CompactLoading18577:14674360 × 56
6ExpandedLoading18577:14679360 × 64
1.0.0 — April 2026Major
Initial Assessment · node 18577:14637
Verdict: Consolidate — Sibling of base Action List; duplicates the 2 × 3 density/state matrix just to add a trailing Counter. Fold into base via a trailing slot. Open
Family
C1 — Duplicated matrix — 6 variants re-created instead of using a slot on the base. Open
C1
C2 — PascalCase namingDensity/State mismatch lowercase state on composed Counter. Open
C2
C4 — Loading skeleton shape — 46 × 16 trailing strip doesn't match a 24 × 24 Counter pill. Open
C4
C7 — Code Connect — Not mapped; wait for consolidation so the mapping targets the base row. Open
C7