East Blue v0.1.0
Component Assessment
Overview
Components
Accordion
Action List - with Counter
Action List - with Description
Action Row
Ad Carousel
Ad
Ad Space
Alert
DM LM
Avatar
Avatar Group
Label Label
Badge
Banner
Bottom Sheet
Button
Callout
Generic Card
Generic Transaction Card
Carousel Card
Carousel Item
Chat Field
Checkbox
Chip
Countdown
Counter
Date Picker
Date Picker - Group
Date Picker - Item
Month and Year Picker - Item
Select
Select Group
Select Item
Empty State
Amount Text Field
Input Field
Labeled Field
Recipient Field
Search Field
Select Field
Text Area
Upload File
View Only Field
Brand App Bar
Detail Hero
Footer
Page Banner
Section Header
Inline Message
Inline Text
List
List Item
List Item Asset
Menu Grid
Modal
Overlay
Progress Bar
Radio Button
Radio Button with Label
Service Item
Slider
Stepper
Stepper - Circular
Stepper - Dash
Subtext Message
Table Row
Table Scheduling
Table Transaction
Tab Item
Tabs
Title Header
Title Bar - App
Toast
Toast - With Button
Segmented Control - Group
Segmented Control Button
Toggle
Toggle - Segmented Control
Toggle - With Label
Tooltip
Tooltip - Onboarding
Tooltip Blurred and Transparent
Tooltip V2
Visual Popup
35%
Horizontal Voucher
Terms & Conditions Accordion
35%
Vertical Voucher
35%
Voucher Asset
Voucher Card Horizontal
Voucher Details
Icons Styles
KeepNeeds Refinement
Ad Carousel Component link

A titled rail that scrolls Ad Space cards sideways, with an optional button in the header. One version, driven by a content slot.

Keep — clean structure, one open family question
The component reads in two levels: a Header holding #title and an optional button, over a ⤷ CarouselSlot that holds the cards. Names match Ad Space exactly, and the slot is the single control for what appears in the rail. It is badged Needs Refinement for one reason: nothing inside it is actually about ads. A title, a button, and a row of cards is the generic rail pattern, so the ad-specific framing is worth revisiting once the Carousel family is reviewed.
In Context

Sits on dashboard and category surfaces as a sponsored rail — a section heading, an optional "Show more" button, and a horizontally scrolling row of Ad Space cards with the next one peeking at the right edge.

Live Preview
Title
Asset
Header
Description Goes Here
Asset
Header
Description Goes Here
Properties
hasCTA
⤷ CarouselSlot
Content
#title
DS Health
Reusable
Pass
The rail is content-agnostic in structure — ⤷ CarouselSlot takes whatever card is dropped into it. Every ad surface that needs a scrolling row uses this one component rather than a bespoke frame.
Self-contained
Pass
Carries its own surface, heading type style, spacing, and clipping behaviour. The button comes from the design system's own Button - XSmall rather than a hand-built shape.
Consistent
Pass
Layer names match Ad Space one for one — Header, #title, and a ⤷ -prefixed slot. The duplicate hand-built button and the spacer node that used to sit in the header are both gone.
Composable
Partial
It nests Ad Space cleanly through the slot. What it cannot do is hold anything else: the component is named and documented for ads, so a dashboard rail of Carousel Cards needs a second component. That is the open family question behind the Needs Refinement badge.
Behavior
State iOS Android Figma Property Notes
hasCTA=false N/A N/A default Heading only. This is the default the component ships with.
hasCTA=true N/A N/A Button - XSmall Adds the "Show more" button at the right of the heading row.
⤷ CarouselSlot N/A N/A content slot Selects which Ad Space version fills the rail. Promo is the default.
Peek N/A N/A overflow clip The rail is wider than the shell, so the next card is cut off at the right edge to signal scrollability.
Issues
  • One button in the heading, not two. The header used to carry a hand-built "Show more" — an offset frame, a spacer, and an arrow — alongside a real Button - XSmall instance saying the same thing. The hand-built one is gone. C1 · Layer Structure & Naming
  • The spacer node is gone. A _space_8 instance was faking a gap between the label and the arrow. Spacer nodes have no native equivalent — auto layout spacing does the job — and it went with the hand-built button. C4 · Native Mappability
  • Names match Ad Space. header-content became Header, and the empty header frame wrapping it was removed. The heading text is #title, the same name Ad Space uses for the same job. C1 · Layer Structure & Naming
  • The one-value setting is gone. The component was a set with a single Type=Default version — a dropdown with nothing to choose. It is now a plain component; what varies is the slot content and hasCTA. C2 · Variant & Property Naming
  • Banner filling the rail edge to edge is intentional. A 320-wide Banner in a 360-wide shell leaves no room for the next card, so nothing peeks — Promo shows about 96px and Receipt about 20px. Confirmed as intended: Banner is the full-width option, and the rail still scrolls. No change to the inset or the gap. C1 · Layer Structure & Naming
  • The next card now actually peeks. With Banner cards in the rail, the second card started exactly on the shell's right edge — nothing showed, so the rail read as a single card. Promo is now the default slot content, which leaves about 96px of the next card visible. C1 · Layer Structure & Naming
Recommendations
  • Revisit whether this should be ad-specific. Strip the name away and this is a heading, an optional button, and a row of cards — the generic rail. Swap Ad Space for Carousel Card and it is the dashboard rail. Keeping it ad-specific was a deliberate call this pass, because calling it Carousel would collide with Carousel Card and Carousel Item. Settle it as a family decision when the Carousel family is reviewed, so the design system does not end up with one rail per card type. Family
  • Give the heading a way to switch off. hasCTA hides the button, but the heading itself is always on. Rails that sit under an existing section heading would repeat it. A hasHeader boolean, matching the has prefix already used for hasCTA, would cover that case. Property
  • Make the button a slot if the label ever varies. The button is a fixed Button - XSmall instance today. If "Show more" ever becomes "See all" or "View offers", promote it to ⤷ ActionSlot, the same pattern Tooltip uses, so the label and icon can change without detaching. Slot
  • Confirm the heading colour is token-bound. #title renders #072592 and the button label #005CE5. Both should resolve to named colours rather than raw values. Worth a Dev Mode check, since the read-only tools used for this assessment report the hex without showing whether a token sits behind it. Token
  • Treat the rail as a list for assistive tech. Expose the rail as a single horizontally scrollable group with the heading as its label, and each card as an element within it, so screen reader users can skip the whole rail instead of stepping through every ad. A11y
  • See siblings: Ad Space supplies every card in the rail. Carousel Card and Carousel Item are the non-ad equivalents and are the reason this component is not simply called Carousel. Family
Structure
Ad Carousel
DES DEV

One version. The heading row carries #title and an optional button; the slot below holds the cards and clips the last one.

Title
Asset
Header
Description Goes Here
Asset
Header
Description Goes Here
Properties
hasCTA
⤷ CarouselSlot
Properties
hasCTA false
⤷ CarouselSlot Ad Space · Promo
#title Title
Button Button - XSmall instance
Colors
Surface #FFFFFF
#title #072592
Button label #005CE5
Layout
Width 360
Height 288
Padding top 12
Side inset 24
Heading to rail 16
Card gap 16
Next card visible 96 (Promo)
Typography
#title style Primary/Bold/Heading
Font Proxima Soft Bold · 18 / 18 · +0.25
Button label Proxima Soft Bold · 14 / 14 · +0.25
EBAdCarousel(title: "Title") {
    ForEach(ads) { ad in
        EBAdSpace(.promo) { ad.image }
    }
}
Installation Planned API

Swift Package Manager

.package(url: "https://github.com/gcash/east-blue-ios", from: "1.0.0")

Gradle

implementation("com.gcash.eastblue:components:1.0.0")

Planned API — the native library does not exist yet. Snippets show the intended shape, not shipped code.

Property Mapping

Figma properties mapped to the intended native parameters.

Figma PropertySwiftUICompose
#title title: String title: String
hasCTA action: EBAdCarouselAction? action: (() -> Unit)?
⤷ CarouselSlot @ViewBuilder content: () -> Content content: @Composable RowScope.() -> Unit
Usage Snippets Planned API
Heading only (default)
EBAdCarousel(title: "Sponsored") {
    ForEach(ads) { EBAdSpace(.promo) { $0.image } }
}
EBAdCarousel(title = "Sponsored") {
    ads.forEach { EBAdSpace(AdSpaceVariant.Promo) { Asset(it) } }
}
With the button (hasCTA=true)
EBAdCarousel(
    title: "Sponsored",
    action: .init(label: "Show more") { router.push(.allAds) }
) {
    ForEach(ads) { EBAdSpace(.promo) { $0.image } }
}
EBAdCarousel(
    title = "Sponsored",
    action = { navController.navigate("ads") }
) {
    ads.forEach { EBAdSpace(AdSpaceVariant.Promo) { Asset(it) } }
}
Accessibility
RequirementiOSAndroid
Rail is one navigable group accessibilityElement(children: .contain) on the rail, labelled by #title Modifier.semantics { collectionInfo = CollectionInfo(1, itemCount) }
Heading is exposed as a heading .accessibilityAddTraits(.isHeader) Modifier.semantics { heading() }
Button reachable without scrolling the rail Button precedes the rail in the accessibility order Button precedes the rail in the traversal order
Clipped card is still reachable Scroll to reveal on accessibility focus bringIntoViewRequester on focus
Usage Guidelines

Do

Use Promo cards when the rail should read as scrollable — about 96px of the next card stays visible.

Don't

Don't expect a peek from Banner cards; at 320 wide they fill the rail by design.

Do

Let the heading describe the whole rail, and switch off the card titles inside it.

Don't

Don't repeat the same wording in the rail heading and in every card.

Do

Turn on the button only when there is somewhere further to go.

Don't

Don't ship a "Show more" that leads back to the same surface.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready Two levels, names matching Ad Space. Banner filling the rail edge to edge is intentional.
C2 Variant & Property Naming Ready The one-value Type setting was removed. hasCTA follows the boolean prefix convention.
C3 Token Coverage Needs Refinement Colours are attested as token-bound but were not verifiable with read-only tools. Needs a Dev Mode confirmation.
C4 Native Mappability Ready The spacer instance is gone. Heading plus scrolling row maps to a lazy row with a header on both platforms.
C5 Interaction State Coverage Not Applicable The container has no states of its own. Pressed behaviour belongs to the cards and the button.
C6 Asset & Icon Quality Needs Refinement The button's arrow uses a shape_full boolean operation — delegated to the iconography team, not fixable here.
C7 Code Connect Linkability Not Mapped Blocked — the native library does not exist yet.
Code Connect
Aspect Status Notes
Property naming Ready hasCTA (bool), #title (text), ⤷ CarouselSlot (slot) map one to one.
Token coverage Needs Refinement Heading and button colours need a Dev Mode check before mapping.
Registration Not Mapped Blocked until the native library exists.
Variants Inventory (2 total)

1 component × 2 hasCTA values = 2 states. Rail content is set through the slot, not through a variant.

hasCTAHeaderNode
false#title only5703:38564
true#title + Button - XSmall5703:38564
1.0.0 — August 2026Initial
First assessment · node 5703:38564
Duplicate Show more removed — the hand-built frame is gone, the Button - XSmall instance stays.
C1 resolved
_space_8 spacer instance deleted with the hand-built button.
C4 resolved
header-content renamed to Header, the redundant header wrapper removed, and the heading text renamed to #title.
C1 resolved
The single-value Type setting removed — the component set became a plain component, which is why the node changed.
C2 resolved
Promo set as the default rail content so the next card peeks. Banner fills the rail edge to edge, confirmed as intentional.
C1 resolved
On this page
Are you looking for Components?
esc