The leading marker in a list item — a status icon, a bullet, a square, a number, or a slot for anything else.
type × indicator × state, 72 theoretical combinations for about ten valid ones — and asked for a single semantic enum plus a real Figma Slot in place of the custom placeholder. The 2026 rebuild is exactly that: one Type axis with eight values and a working ⤷ IconSlot. This pass closed the naming that was left: the spaces came out of the multi-word values, the bullet became a real ellipse instead of a rounded rectangle, and the numbered text layer got a name instead of being called after its own content. Nothing is outstanding on the component itself; Code Connect stays open because the native library does not exist yet.Shown three-up against label lines, which is how the marker is actually read — on its own a 5px dot tells you nothing. The composed row lives in List Item.
⤷ IconSlot rather than needing a ninth.PendingNotice, CheckPositive), the shape layers are Circle and Square, the text layer is #number, and the slot is ⤷ IconSlot — the same conventions settled across Voucher, Countdown and Modal.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Type=Pending | N/A | N/A | 16 × 20 | Clock icon in the neutral marker colour. The default the component ships with. |
| Type=PendingNotice | N/A | N/A | 16 × 20 | The same clock path in amber — pending that needs attention. |
| Type=Check | N/A | N/A | 16 × 20 | Checkmark in the neutral marker colour — done, without asserting success. |
| Type=CheckPositive | N/A | N/A | 16 × 20 | The same checkmark path in green — done and successful. |
| Type=Bullet | N/A | N/A | 9 × 20 | A 5px filled ellipse for unordered lists. |
| Type=Square | N/A | N/A | 9 × 20 | A 5px rounded square — the second-level bullet. |
| Type=Numbered | N/A | N/A | 12 × 20 | #number carries the index and is overridden per item. Ships as "1."; the version hugs, so double-digit indices grow it rather than clipping. |
| Type=Slot | N/A | N/A | 16 × 20 | An empty 16 × 20 slot. Deliberately ships with no default so nothing has to be cleared before swapping. |
- Three entangled axes became one. The old build multiplied
type×indicator×stateinto 72 theoretical combinations for roughly ten valid ones. It is now a singleTypeenum with eight values, which is what the first assessment asked for. C2 · Variant & Property Naming - The custom placeholder is a real slot.
Customused to be a placeholder circle that product teams had to instance-swap around. It is now⤷ IconSlot, a genuine Figma Slot taking any 16 × 16 asset. C6 · Asset & Icon Quality - The multi-word values lost their spaces.
Pending NoticeandCheck PositivebecamePendingNoticeandCheckPositive. Enum values become native cases, so a space would have forced a rename at the Code Connect boundary — the same fix applied to Modal'sActionOrientation. C2 · Variant & Property Naming - The bullet is a real ellipse. It was a
RECTANGLEwith a 3px corner radius namedcircle— geometrically a circle at 5 × 5, so it rendered correctly, but the node type contradicted the name and would have exported as a rounded rect. It is now a trueELLIPSEnamedCircle. C6 · Asset & Icon Quality - The numbered text layer has a name. It was called
1.— named after its own content, which is the layer every numbered list overrides. It is now#number, following the#-prefix convention, so it can be addressed as a parameter. C1 · Layer Structure & Naming - The shape layers are PascalCase.
circleandsquarebecameCircleandSquare, matching the convention used across the rest of the system. C1 · Layer Structure & Naming - The status recolours are first-class types, deliberately. Check and CheckPositive are byte-identical paths differing only in stroke colour (
#90A8D0to#27C990), and the same is true of Pending and PendingNotice (#90A8D0to#CA970C). That normally reads as a second axis hiding inside the first, and the alternative was to route all four through the slot and cutTypeto four values. Confirmed as intentional instead: the colours carry status meaning rather than styling, so they belong in the enum where a designer picks them by name. C2 · Variant & Property Naming - Hollow was dropped on purpose. The first assessment's target enum included a
hollowmarker. It is absent from the rebuild by design — structurally identical to Bullet, so it would have been a second name for one shape. C2 · Variant & Property Naming - The empty slot is deliberate.
⤷ IconSlotships with no default content. Confirmed as intended rather than an omission — the slot exists to be filled, and a placeholder would have to be cleared first. C5 · Interaction State Coverage - Numbered hugs its content, so double digits fit. The version measures 12 wide with
#numberrendering "1." at 9, which would clip a two-digit index like "10." if the width were fixed. Confirmed that it hugs instead — the 12 is the hug width for a single digit, and the version grows with the number. Numbered lists can run past nine items. C1 · Layer Structure & Naming - The vertical offsets are hand-set. Inside the 20px box the icons sit at offset 2 and are centred, while
CircleandSquaresit at 8 and#numberat 4 — neither geometrically centred. Confirmed as manual optical alignment against the label's line box, not drift. C1 · Layer Structure & Naming
- Write down that markers are not mixed within a list. The versions are 16, 12 and 9 wide, so a list mixing a Check with a Bullet would not align down its left edge. Confirmed that mixing is out of scope by design and that users will be briefed — but the constraint is invisible from the component itself, so it belongs in the usage documentation where someone reaches for it. Docs
- Keep the two status colours token-bound. Because CheckPositive and PendingNotice are the same artwork recoloured, their colour is the entire difference between them and their neutral siblings. If either override ever drifts to a raw hex, the distinction silently stops tracking the palette. Token
- Give the status markers an accessible label. Bullet, Square and Numbered are decorative — the list's own semantics carry the structure, so they should be hidden from assistive tech. Check, CheckPositive, Pending and PendingNotice are not decorative: they carry the item's status and need that status in text, or a screen reader user gets the label with no indication of state. A11y
- Pass the icon-grid scaffolding upstream. The Pending and Checkmark instances each nest a
Gridtemplate carryingGuide lines,KeyshapesandTrim areawith red construction strokes. They are hidden and do not render, so this is not a fault here, but they ship inside every instance and belong to the icon library rather than to this component. Docs - See siblings: List Item is the row this marker sits in, and it is the only other component in the family — List was removed in the 2026 rebuild, so rows are stacked with auto layout rather than by a container component. Family
One colour per version, and only one — the marker paints nothing behind it, so the list surface shows through. Status is carried entirely by the fill: the same clock path is neutral or warning, and the same checkmark is neutral or success.
| Role | Token | Value |
|---|---|---|
| Pending | text/color-text-weakest | #90A8D0 |
| PendingNotice | text/color-text-warning | #CA970C |
| Check | text/color-text-weakest | #90A8D0 |
| CheckPositive | border/color-border-success | #27C990 |
| Bullet | text/color-text-weakest | #90A8D0 |
| Square | text/color-text-weakest | #90A8D0 |
| Numbered | text/color-text-weakest | #90A8D0 |
| Slot | none — supplied by the instance | — |
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:list:1.0.0")
Import
import EastBlueDS import com.eastblue.ds.list.*
Planned API — the native library does not exist yet. The artifact is the List family: List, List Item and List Item - Asset all ship in <code>com.eastblue.ds:list</code> and import <code>com.eastblue.ds.list.*</code>.
Two properties: one enum and one slot. #number is deliberately absent — it is a text layer inside the Numbered variant, not a component property, so a designer setting a list to 3. is overriding the layer rather than a value Code Connect can bind. Natively it has to be a parameter regardless, so the API carries number alongside the enum and the two are wired together at the call site.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| Type — Pending, PendingNotice, Check, CheckPositive, Bullet, Square, Numbered, Slot | type: EBListItemAssetType | type: EBListItemAssetType |
| ⤷ IconSlot (slot) | @ViewBuilder icon: () -> Icon — Slot only | icon: @Composable (() -> Unit)? — Slot only |
EBListItemAsset(type: .pending)
EBListItemAsset(type = EBListItemAssetType.Pending)
EBListItemAsset(type: .pendingNotice)
EBListItemAsset(type = EBListItemAssetType.PendingNotice)
EBListItemAsset(type: .check)
EBListItemAsset(type = EBListItemAssetType.Check)
EBListItemAsset(type: .checkPositive)
EBListItemAsset(type = EBListItemAssetType.CheckPositive)
EBListItemAsset(type: .bullet)
EBListItemAsset(type = EBListItemAssetType.Bullet)
EBListItemAsset(type: .square)
EBListItemAsset(type = EBListItemAssetType.Square)
EBListItemAsset(type: .numbered, number: 3)
EBListItemAsset(type = EBListItemAssetType.Numbered, number = 3)
EBListItemAsset(type: .slot) { Image(systemName: "star.fill") }
EBListItemAsset(type = EBListItemAssetType.Slot) { Icon(EBIcons.Star) }
| Requirement | iOS | Android |
|---|---|---|
| Decorative markers are hidden | Bullet, Square and Numbered use .accessibilityHidden(true) | Bullet, Square and Numbered use contentDescription = null |
| Status markers carry their status in text | Check, Pending and their tones set accessibilityLabel on the row, not the icon | Status is folded into the row's contentDescription |
| Colour is not the only signal | CheckPositive versus Check must differ in the announced text, not just in green | Same — the tone difference is invisible to a screen reader |
| Ordered lists expose their index | #number maps to the row's position, not a decorative glyph | CollectionItemInfo carries the index |
Do
Pick one marker type and use it for every item in the list.
Don't
Don't mix types in one list — the versions are 9 to 16 wide and the labels stop aligning.
Do
Use CheckPositive when success is the point, Check when the item is merely done.
Don't
Don't use the tones decoratively — they read as status.
Do
Reach for the slot when the enum has no marker for the job.
Don't
Don't add a ninth version for a one-off icon.
Do
Override #number per item.
Don't
Don't leave every row showing "1.".
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | Circle, Square and #number all renamed this pass. The hand-set vertical offsets are confirmed as optical alignment. |
| C2 | Variant & Property Naming | Ready | One axis where there were three. Multi-word values joined to PendingNotice and CheckPositive; the status tones are deliberate enum members rather than a hidden second axis. |
| C3 | Token Coverage | Ready | Every marker colour is bound and named: text/color-text-weakest for the six neutral versions, text/color-text-warning for PendingNotice, border/color-border-success for CheckPositive. Slot paints nothing — the swapped instance carries its own colour. |
| C4 | Native Mappability | Ready | An enum and a slot map to a single view or composable with no web-only pattern in the way. One constraint to carry across: the marker box is 16, 12 or 9 wide depending on the version, so a list that mixes them starts its labels at different x positions. That is the component as built and shipped; raising it belongs in Design Recommendations, not here. |
| C5 | Interaction State Coverage | Not Applicable | Display only — the marker is never the tap target. Pressed behaviour belongs to List Item. |
| C6 | Asset & Icon Quality | Ready | The bullet is a true ellipse after this pass, and the custom placeholder is a real slot. The icons nest hidden grid scaffolding, which belongs to the icon library. |
1 component set × 8 Type values = 8 variants. Four are status markers in two tones, three are list decorations, and the last is the escape hatch.
| Type | Box | Marker | Colour | Node |
|---|---|---|---|---|
| Pending | 16 × 20 | Clock icon | #90A8D0 | 5698:43261 |
| PendingNotice | 16 × 20 | Clock icon — same path | #CA970C | 5698:43263 |
| Check | 16 × 20 | Checkmark | #90A8D0 | 5698:43265 |
| CheckPositive | 16 × 20 | Checkmark — same path | #27C990 | 5698:43267 |
| Bullet | 9 × 20 | Circle — ellipse 5 × 5 | #90A8D0 | 5698:43269 |
| Square | 9 × 20 | Square — 5 × 5, radius 1 | #90A8D0 | 5698:43273 |
| Numbered | 12 × 20 — hugs | #number — 14 / 14 | #90A8D0 | 5698:43275 |
| Slot | 16 × 20 | ⤷ IconSlot — empty | consumer | 5698:43280 |
.eb-preview-lia declared font-family: inherit, which resolves to the site’s --font-body — BarkAda. #number carries Primary/Label/Light/Small and is Proxima Soft in Figma, so the one piece of type in the component was rendered in the wrong face. The root now names Proxima Soft. The sample label beside each marker is not a layer of this component — it stands in for a List Item label — so it takes BarkAda, which is what that label actually is.Type is the driving property, so each of its values gets a card — Pending, PendingNotice, Check, CheckPositive, Bullet, Square, Numbered, Slot, in the panel’s order. The single card was titled with the component’s own name and described Type=Pending only, so seven versions had no specification at all.Marker size, Top offset, Corner radius and a single Padding, with no Gap or Alignment. All seven are now read off the Figma auto-layout panel rather than derived from bounding boxes.Proxima Soft SemiBold · 14 / 14 · +0.25 and "shared library style · name pending Dev Mode read". #number resolves to Primary/Label/Light/Small. The seven versions with no text layer now say so, rather than showing an em dash that would read as a failed lookup.text/color-text-weakest for the six neutral versions, text/color-text-warning for PendingNotice, border/color-border-success for CheckPositive. A Colors by Type table carries all eight; the page had no colours table before.shape_full with its fill; Check and CheckPositive return only the icon’s hidden guide layer, because their checkmark is a stroked path rather than a filled shape. Exporting the variant as SVG returns the vector with stroke="#27C990" on it, which reads what get_node_info cannot and confirmed the token bindings independently.Node duplicated the card’s own node field, and Overridable and Ships as described the component rather than specifying it. ⤷ IconSlot now appears on the Slot card, where it exists.Type is the driving property and ⤷ IconSlot is a slot, so there is genuinely nothing to control — the explicit empty array is what the guides settled for this case.gcash/east-blue-ios and com.gcash.eastblue:components:1.0.0, with no Import line. It now cites the List family artifact com.eastblue.ds:list:1.0.0 and imports com.eastblue.ds.list.*.#number, which the Figma panel does not expose. Two rows now, each carrying all its values, with #number explained in the description instead.#number is a text layer, not a component property. Setting a list to 3. means overriding the layer, so there is nothing for Code Connect to bind the index to when the native library lands. Recorded against C7, which was already open on registration..numbered(Int) — an enum with an associated value — while the Style tab’s DEV code emitted a plain .numbered. Settled toward a separate number parameter; all eight calls are now byte-identical across the two tabs.Type value now, eight in total.getSnippet, so both language tabs were frozen on a static string; they now render eight distinct SwiftUI and Compose calls. Code Connect’s three readiness rows described a registration that cannot happen yet.type × indicator × state axes became a single Type enum with eight values, closing the first assessment's main recommendation.⤷ IconSlot now takes any 16 × 16 asset without instance-swapping. Deliberately ships empty.1. is now #number, addressable as a parameter instead of named after its own content.Pending Notice and Check Positive renamed to PendingNotice and CheckPositive — enum values become native cases, so the spaces had to go.RECTANGLE with a 3px radius named circle. Both shape layers are now PascalCase Circle and Square.hollow dropped from the target enum — structurally identical to Bullet, so it would have been a second name for one shape.18482:34406 (Sticker Sheets v2) to 5698:43260 (2026 Working File).variant enum. Opennumber parameter. Open