A full-bleed banner item for a horizontal carousel — background image, heading, description, and a button. 24 versions across size, appearance, top element, and pressed state.
Carousel Item, and every issue from the first assessment is closed. Settings are now Size, Appearance, TopElement, and isPressed — a full 2 × 2 × 3 × 2 grid with all 24 versions built, no gaps. Background and ⤷ LeadingIcon are real slots, the chevron is a vector instance inside a proper Button, and pressed ships as a dim overlay. Code Connect stays unmapped because the native library doesn't exist yet.Carousel - Item is one card in a horizontal swipe carousel — typically a promotional banner stack on the Home or Dashboard screen. The center item is emphasized; side items peek in at reduced opacity/scale. In today's Figma file, those visual states exist as separate components (Item, Item - Center, Item - Side) rather than being driven by the carousel container.
Background is a slot, so any team drops in its own artwork without detaching. One component now covers what took three.Overlay instance rather than left to the consumer.Background, content, top-container, text-container, Button_New. Settings follow the naming guidelines: Size, Appearance, and TopElement in PascalCase, isPressed as an is-prefixed boolean with true / false values.Trailing Container slot. Stacks into a horizontal scroller; the carousel container itself is still undocumented and tracked as a recommendation.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default | Yes | Yes | Size=Default | 282 × 160. Background slot, heading, description, and a button with a trailing chevron. |
| Small | Yes | Yes | Size=Small | 282 × 146. Same anatomy, 14px shorter. These are the two heights the old Center and Side components used, so a carousel that shrinks its side items swaps versions rather than applying a transform. |
| Dark appearance | Yes | Yes | Appearance=Dark | For dark artwork — heading in #ffffff, description in #f6f9fd at 80%. |
| Light appearance | Yes | Yes | Appearance=Light | For pale artwork — dark text. Note the inversion from the old mode setting: what was mode=Light Text is now Appearance=Dark. |
| Top element | Yes | Yes | TopElement=Icon | Preamble | None | Chooses what sits above the heading — a 24 × 24 ⤷ LeadingIcon slot, a preamble line, or nothing. |
| Pressed | Yes | Yes | isPressed=true | An Overlay instance drops a dim layer over the background at #020e22 / 24%. Text colours stay put. |
| Loading | N/A | N/A | Not built | No skeleton. Carousel Card ships one — deferred for now, tracked as a family-consistency item. |
- Code Connect mappings not registered. Blocked — the native component library doesn't exist yet. Nothing to action on the design side. C7 · Code Connect Linkability
- The three sibling components are now one. v2.0: rebuilt on node
5776:37969. Item, Center, and Side collapsed into a singleCarousel Item, and what was carousel position is now aSizesetting —Default(282 × 160) andSmall(282 × 146). C1 · Layer Structure & Naming - Property names follow the guidelines. v2.0:
Size,Appearance, andTopElementare PascalCase variant properties;isPressedis anis-prefixed boolean with lowercasetrue/false; the slot is⤷ LeadingIcon. The old mix ofhasPreamble,with Icon, andLight Textis gone. C2 · Variant & Property Naming -
type=Headline Onlyis gone. v2.0: replaced byTopElement = Icon | Preamble | None, which names what actually changes — the element above the heading. C2 · Variant & Property Naming -
modebecame a real appearance setting. v2.0: nowAppearance = Dark | Light, picking the whole text colour set at once instead of overriding layers. Watch the inversion — the oldmode=Light Textis the newAppearance=Dark. C4 · Native Mappability - The background is a slot. v2.0:
Backgroundis a SLOT on all 24 versions, wrapping anAssetinstance. Teams drop in their own artwork without detaching. C4 · Native Mappability - The chevron is a vector instance. v2.0: now
Chevron Right Small, riding in the button'sTrailing Containerslot. The rastershape_fullis gone, and it ships once rather than once per appearance. C6 · Asset & Icon Quality - The icon placeholder is a slot. v2.0:
⤷ LeadingIcon(5804:42380) is an empty 24 × 24 slot in place of the drawn grey circle. Any DS icon or Avatar drops in. C6 · Asset & Icon Quality - The card has a pressed state. v2.0:
isPressedships on all 24 versions. AnOverlayinstance dims the background with a#020e22layer at 24%, leaving text colours untouched. C5 · Interaction State Coverage
- Note why
SizeusesDefaultandSmall. The standard size scale isXS · SM · MD · LG · XL. This component deliberately usesDefaultandSmallto put the emphasis on the default behaviour. Write the exception down so the next reviewer doesn't file it as drift. Docs - Settle the
Button_Newname. The button instance inside every version is namedButton_New, which reads like a migration artifact. Held for the final reviewer to decide — it belongs to the Button component, not this one. Rename - Decide whether Carousel Item needs a loading state. Carousel Card ships
isLoadingwith skeletons; this component has none. Deferred for now. Settle it either way so the card family stays predictable. State - Audit the colour token bindings. The review tooling reads raw hex and can't see which values are bound to variables, so C3 is recorded as unverified rather than passing. The description colour in particular is
#f6f9fdat 80% opacity rather than a flat token value — worth confirming that's the intended binding. Token - Document the carousel container. Peek behaviour, snap-to-centre, the page indicator, and auto-advance belong on a dedicated
EBCarouselcontainer — not on each item. On iOS that's.scrollTransition; on Android,graphicsLayerkeyed offHorizontalPagerpage offset. Family - Announce as a link or button. The whole card is tappable — VoiceOver and TalkBack should read heading, description, and the button label as one actionable announcement. A11y
- See siblings: Carousel Card — the narrow 140-wide card for the same rails. Keep slot naming and state coverage aligned across both. Family
- Consolidate Carousel - Item + Center + Side into a single
Carousel Item. v2.0: Applied — one component replaces three. Position became theSizesetting. Family - Add a
backgroundslot. v2.0: Applied —Backgroundis a SLOT on all 24 versions. Slot - Replace
modewith anappearanceenum. v2.0: Applied —Appearance = Dark | Lightnow picks the whole text colour set. Property - Rename
type=Headline Only. v2.0: Applied — replaced byTopElement = Icon | Preamble | None. Rename - Add a leading icon slot. v2.0: Applied —
⤷ LeadingIcon, an empty 24 × 24 slot. Slot - Vectorize the chevron. v2.0: Applied —
Chevron Right Smallinstance inside the button'sTrailing Containerslot. Asset - Add pressed state. v2.0: Applied —
isPresseddims the background via anOverlayinstance at#020e22/ 24%. State
The most common variant — heading + description + button link, inverse text over a dark background image. Used on promotional carousels when the photo has dark tones.
Single carousel slide with heading and description on a white surface.
| Role | Token | Default |
|---|---|---|
| Heading | carousel/color/label-header | #2340A9 |
| Description | carousel/color/description | #6780A9 |
| Surface | bg/color-bg-main | #FFFFFF |
| Active dot | bg/color-bg-primary | #005CE5 |
Preamble + headline only — no description line. Use when the headline itself is the full message. Name is misleading: the variant actually requires Preamble + Heading + Button, with description hidden.
Same palette as Card 1 — variant differs in slot composition, not color.
| Role | Token | Default |
|---|---|---|
| Heading | carousel/color/label-header | #2340A9 |
| Description | carousel/color/description | #6780A9 |
| Surface | bg/color-bg-main | #FFFFFF |
| Active dot | bg/color-bg-primary | #005CE5 |
| Figma Property | SwiftUI | Compose |
|---|---|---|
mode: Light Text | Dark Text | appearance: light | dark | .ebAppearance(.light) |
type: Default | with Icon | Headline Only | type: default | withIcon + hasDescription: Bool | leadingIcon: Image?, hasDescription: Bool |
hasPreamble | preamble?: String | preamble: String? |
hasTextLink | actionLabel?: String | actionLabel: String? |
| (baked raster background) | background: Image | Gradient (slot) | background: AnyView |
| (drawn grey circle) | part of leadingIcon slot | leadingIcon: Image? |
| (raster chevron) | showChevron: Bool (vector) | showChevron: Bool = true |
| (not modeled) | onTap: () -> Void | onTap: (() -> Void)? |
| Carousel - Item | merge into Carousel Item | position is carousel-container-driven |
| Requirement | iOS | Android |
|---|---|---|
| Whole-card tap target | Wrap in Button with combined accessibilityLabel (preamble + heading + description + action). | Modifier.clickable().semantics(mergeDescendants = true). |
| Page-change announcements | Announce current page index via accessibilityValue on the carousel container. | semantics { contentDescription = "Banner 2 of 5" } on the pager. |
| Contrast on image | Designer ensures 4.5:1 between text + underlying image area; optional scrim overlay. | Same — ensure WCAG AA against the image region. |
| Reduce motion | Skip scale + opacity transitions when UIAccessibility.isReduceMotionEnabled. | Check Settings.Global.TRANSITION_ANIMATION_SCALE; skip graphicsLayer animation. |
| Min touch target | 282×160 ≫ 44 pt ✓ | 282×160 ≫ 48 dp ✓ |
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | One component replaces three. All 24 versions share Background, content, top-container, text-container. |
| C2 | Variant & Property Naming | Ready | Size, Appearance, TopElement in PascalCase; isPressed boolean with lowercase values. Size=Default|Small is a deliberate exception to the XS–XL scale. |
| C3 | Token Coverage | Needs Refinement | Not verified. The read-only review tooling reads raw hex and can't see variable bindings. No evidence of a problem, but a token audit is needed to close this out — the 80% opacity on the description colour is worth confirming. |
| C4 | Native Mappability | Ready | Background and ⤷ LeadingIcon map to @ViewBuilder / @Composable slots. Size and Appearance are plain enums. |
| C5 | Interaction State Coverage | Ready | Default and pressed built across all 24. No loading state — deferred, tracked as a family-consistency item. |
| C6 | Asset & Icon Quality | Ready | Vector Chevron Right Small instance; ⤷ LeadingIcon slot; Background slot. |
| C7 | Code Connect Linkability | Not Mapped | Blocked — the native component library doesn't exist yet. |
mode (2) × type (3) × hasTextLink (2) × hasPreamble (2) = 24 combinatorial variants, but only 10 are modeled — the author pruned invalid combinations (e.g. Headline Only without Preamble, with Icon with TextLink). Each mode has 5 variants.
| Mode | Type | hasTextLink | hasPreamble | Node | Dimensions |
|---|---|---|---|---|---|
| Light Text | Default | yes | no | 18543:2807 | 282 × 160 |
| Light Text | with Icon | no | no | 18543:2818 | 282 × 160 |
| Light Text | Default | yes | yes | 18543:2826 | 282 × 160 |
| Light Text | Headline Only | yes | yes | 18543:2839 | 282 × 160 |
| Light Text | Default | no | no | 18543:2850 | 282 × 160 |
| Dark Text | Default | yes | no | 18543:2856 | 282 × 160 |
| Dark Text | with Icon | no | no | 18543:2867 | 282 × 160 |
| Dark Text | Default | yes | yes | 18543:2875 | 282 × 160 |
| Dark Text | Headline Only | yes | yes | 18543:2888 | 282 × 160 |
| Dark Text | Default | no | no | 18543:2899 | 282 × 160 |
hasPreamble vs with Icon); Headline Only mis-named. Openmode should be appearance. Open