East Blue
KeepReady
Ad Space Component link

A container for ads, promos, and sponsored placements. Three versions — Receipt, Banner, and Promo — each built around one swappable asset area.

Keep — rebuilt on a clean three-version shape
All four DS Health traits pass. The old seven-size schema is gone: the component is now three versions on a single Variant setting, each built the same way — Container wrapping a ⤷ AssetSlot and an optional Content block. Layer names share one vocabulary across every version. Media flows through the slot, so no campaign artwork ships inside the design system. Code Connect stays unmapped because the native library doesn't exist yet — a dev-side dependency, not a design gap.
In Context

Each version has a home in the app: Receipt sits inside transaction and receipt flows, Banner runs inline in a feed or content column, and Promo is the dashboard tile that also fills the Ad Carousel rail.

Live Preview
Title
Asset
Header
Description Goes Here
Properties
Variant
Content
Title
Header
Description
DS Health
Reusable
Pass
One shape covers every ad placement — receipt inserts, in-feed banners, and dashboard promo tiles. The asset area is a real slot, so a product team drops in its own media without asking for a new component.
Self-contained
Pass
Ships its own container, text styles, corner radius, and slot placeholder. No campaign artwork lives inside the design system, and nothing about a specific surface is baked in.
Consistent
Pass
All three versions read the same way: Container → ⤷ AssetSlot → Content. Text layers share one vocabulary — #title, #header, #description — so the same name means the same thing everywhere.
Composable
Pass
Drops into the Ad Carousel rail through ⤷ CarouselSlot, and stands alone inline. No sibling component per placement.
Behavior
State iOS Android Figma Property Notes
Variant=Receipt N/A N/A EBAdSpace(.receipt) 300 × 250. Asset only — no text.
Variant=Banner N/A N/A EBAdSpace(.banner) 320 × 262. Carries #title above the asset.
Variant=Promo N/A N/A EBAdSpace(.promo) 224 × 208. Fills the Ad Carousel rail.
⤷ AssetSlot N/A N/A content slot Swappable area for product-supplied media.
Issues
  • The setting holds versions, not sizes. The Size setting was renamed to Variant. Its values — Receipt, Banner, Promo — name where the ad goes, which is what they always described. Size is reserved for XS–XL under the naming guidelines. C2 · Variant & Property Naming
  • All three versions share one anatomy. Receipt used to hang its asset area straight off the root while the other two wrapped theirs. It now has the same Container, so every version reads Container → ⤷ AssetSlot. The slot was renamed to ⤷ AssetSlot in all three, matching the convention Tooltip uses. C1 · Layer Structure & Naming
  • Text layers no longer contradict their contents. A layer called #label held the text "Title", while a different layer called #title held "Header". They are now #title and #header — each name matches what it holds, in every version. C1 · Layer Structure & Naming
Recommendations
  • Retire the old component in Sticker Sheets v2. This assessment now points at 6507:74166 in the 2026 Working File. The previous component at 18563:9789 is deprecated. Swap the remaining Figma usages, then delete it along with the Placeholder Banner and Promo Cards Images asset libraries once zero usage is confirmed. Family
  • Ship imagery as product assets, not design system assets. Product teams export their own 1×/2×/3× images and pass them into ⤷ AssetSlot. The design system ships the container, type styles, radius, and slot placeholder — never the artwork. Asset
  • Revisit whether the carousel container should stay ad-specific. Ad Carousel is a title, an optional button, and a rail of cards — nothing in it is about ads. Swap Ad Space for a Carousel Card and it becomes the dashboard rail. Keeping it ad-specific was a deliberate call this pass, to avoid a name collision with Carousel Card and Carousel Item. Worth revisiting when the Carousel family is reviewed. Family
  • Propose a main/ad-space/color/* token namespace. Ship main/ad-space/color/surface, main/ad-space/color/title, main/ad-space/color/header, and main/ad-space/color/description. A dedicated namespace makes dark mode and partner-branded surfaces tractable instead of inheriting generic background tokens. Token
  • Bake impression and tap tracking into the native component. The iOS view and Android composable should emit onImpression (50% visible for at least one second) and onTap. Document the contract in the Code tab so every consumer team wires analytics the same way. Docs
  • Treat ads as labeled buttons, not decorative images. Every Ad Space is tappable and leads somewhere, so the whole surface should expose one accessibility label built from #header and #description, plus an "Advertisement" trait to meet App Store and Play Store disclosure norms. A11y
  • Watch the Banner title override inside the carousel. Banner carries #title above the asset, Promo has only #header and #description, and Receipt has no text. Inside Ad Carousel the Banner title is switched off on each copy so it doesn't repeat the rail heading. That is a per-copy override rather than a property, so a designer who swaps the copy gets the title back. A hasTitle boolean would remove the risk if it proves annoying in practice. Slot
  • See siblings: Ad Carousel wraps this component in a scrolling rail. Keep the asset slot and placeholder treatment aligned with Carousel Card as the Carousel family is reviewed. Family
Versions
Receipt
Asset
Properties
Variant Receipt
⤷ AssetSlot Slot Block placeholder
#title —
#header / #description —
Colors
Surface Transparent
Slot placeholder #9F3DFB
Typography
Text layers none
Layout
Height 250px
Width 300px
Radius 4px
Padding H 0px (derived)
Padding V 0px (derived)
Receipt — Colors

Asset only. The purple slot placeholder is an authoring aid and never renders in product.

Role Token Value
Surface — no fill bound Transparent
Banner
Title
Asset
Header
Description Goes Here
Properties
hasTitle
hasDescription
Title
Header
Description
Properties
Variant Banner
⤷ AssetSlot Slot Block placeholder
#title Title
#header Header
#description Description Goes Here
Colors
Surface Transparent
#title #072592
#header #005CE5
#description #445C85
Typography
#title Primary/Label/Large
#header Primary/Label/Large
#description Secondary/Bold/Caption
Layout
Height 262px
Width 320px
Radius 4px
Padding H 0px (derived)
Padding V 0px (derived)
Gap 16px (derived)
Alignment Leading (derived)
Banner — Colors

Three text roles. #title and #header share a size and weight but not a colour.

Role Token Value
Surface — no fill bound Transparent
#title text/color-text-stronger #072592
#header text/color-text-primary #005CE5
#description text/color-text-weak #445C85
Promo
Asset
Header
Description Goes Here
Properties
hasDescription
Header
Description
Properties
Variant Promo
⤷ AssetSlot Slot Block placeholder
#title —
#header Header
#description Description Goes Here
Colors
Surface Transparent
#header #005CE5
#description #445C85
Typography
#header Primary/Label/Large
#description Secondary/Bold/Caption
Layout
Height 208px
Width 224px
Radius 4px
Padding H 0px (derived)
Padding V 0px (derived)
Gap 16px (derived)
Alignment Leading (derived)
Promo — Colors

Same palette as Banner, minus the title role.

Role Token Value
Surface — no fill bound Transparent
#header text/color-text-primary #005CE5
#description text/color-text-weak #445C85
Installation Planned API

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:ad-space:1.0.0")

Import

import EastBlueDS
import com.eastblue.ds.adspace.*

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
Variant — Receipt, Banner, Promo AdSpaceVariant (.receipt / .banner / .promo) variant = AdSpaceVariant.Receipt / Banner / Promo
hasTitle — true, false (Banner only) title: String? — nil hides it title: String? = null
hasDescription — true, false (Banner, Promo) description: String? — nil hides it description: String? = null
Title (text) — Banner only title: String? title: String?
Header (text) — Banner, Promo header: String? header: String?
Description (text) — Banner, Promo description: String? description: String?
⤷ AssetSlot (slot) @ViewBuilder content: () -> Content content: @Composable BoxScope.() -> Unit
Usage Snippets Planned API
Receipt — asset only
EBAdSpace(.receipt) {
    Image(ad.creative).resizable()
}
EBAdSpace(variant = AdSpaceVariant.Receipt) {
    AsyncImage(model = ad.creative, contentDescription = null)
}
Banner — title above, text beneath
EBAdSpace(
    .banner,
    title: "Sponsored",
    header: ad.headline,
    description: ad.blurb
) { Image(ad.creative).resizable() }
EBAdSpace(
    variant = AdSpaceVariant.Banner,
    title = "Sponsored",
    header = ad.headline,
    description = ad.blurb
) { AsyncImage(model = ad.creative, contentDescription = null) }
Promo — asset with header and description
EBAdSpace(
    .promo,
    header: "Header",
    description: "Description Goes Here"
) {
    Image(ad.creative).resizable()
}
EBAdSpace(
    variant = AdSpaceVariant.Promo,
    header = "Header",
    description = "Description Goes Here"
) {
    AsyncImage(model = ad.creative, contentDescription = null)
}
Accessibility
RequirementiOSAndroid
The whole card is one tappable element .accessibilityElement(children: .combine) with a single .isButton trait Modifier.clickable on the container, children marked clearAndSetSemantics
Disclosed as advertising .accessibilityHint("Advertisement") contentDescription prefixed with "Advertisement"
Label built from the text layers #header then #description, joined Same order in contentDescription
Asset is not announced separately .accessibilityHidden(true) on the image contentDescription = null on the image
Minimum tap target 44 × 44 pt — every version clears it at its documented size 48 × 48 dp — every version clears it at its documented size
Dynamic type #header and #description scale to AX5; the asset keeps its ratio sp units on both text roles; the asset keeps its ratio
Usage Guidelines

Do

Pass campaign artwork into ⤷ AssetSlot from the product's own asset pipeline.

Don't

Don't add campaign images to the design system library.

Do

Use Promo inside an Ad Carousel when the rail should read as scrollable.

Don't

Don't expect a peek from Banner in a rail; at 320 wide it fills the shell by design.

Do

Let Receipt carry no text where the surrounding screen already gives context.

Don't

Don't force a header onto Receipt by detaching the copy.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready All three versions read Container → ⤷ AssetSlot. Text layers renamed so each name matches its contents.
C2 Variant & Property Naming Ready Size renamed to Variant; values name the placement, which is what they always described.
C3 Token Coverage Needs Refinement Text roles bind to text/color-text-stronger, text/color-text-primary and text/color-text-weak, confirmed by design. No surface token — the container ships no fill. A main/ad-space/color/* namespace is recommended — see Overview.
C4 Native Mappability Ready A container with an image slot and two optional text rows maps directly to both platforms.
C5 Interaction State Coverage Not Applicable Display-only surface — confirmed by design. Tap handling belongs to the host.
C6 Asset & Icon Quality Ready No raster ships inside the component. The Slot Block placeholder is the standard authoring aid.
Variants Inventory (3 total)

1 Variant setting × 3 values = 3 versions. Content is supplied through the slot and the text layers, not through extra versions.

VariantSizeText layersNode
Receipt300 × 250none6518:74485
Banner320 × 262#title · #header · #description5703:38546
Promo224 × 208#header · #description6528:77243
2.0.6 — September 2026Patch
Preview typeface corrected — node 6507:74166
The preview rendered Primary text in the wrong typeface. Every Primary/* layer is Proxima Soft and every Secondary/* layer is BarkAda, but the preview never said so: the root declared font-family: inherit, which resolves through .eb-preview-scope to body — the documentation font, BarkAda. #title and #header are Primary/Label/Large and were drawing in BarkAda. #description looked right only by accident — it is Secondary/Bold/Caption, and BarkAda is what Secondary resolves to, so the fallback happened to land on the correct face. The root now declares Proxima Soft and the description declares BarkAda, so both are right by intent rather than by luck.
Docs
2.0.5 — September 2026Patch
Receipt's empty control panel is now declared — node 6507:74166
Receipt declares "demoControls": []. Its only properties are the driving Variant and the ⤷ AssetSlot slot, both skipped by the Style guide, so the card correctly has no controls. Omitting the key read as an oversight to the preview lint; declaring it states the intent.
Docs
Every typography row was re-read from Figma. The five text layers across Banner and Promo each return a text style id that resolves through the style database — Primary/Label/Large and Secondary/Bold/Caption, unchanged. The names had been supplied by hand before the database existed; they are now sourced from the component.
C3 Resolved
2.0.4 — September 2026Patch
Overview panel uses the property names — node 6507:74166
The Overview playground labelled the text controls with layer names. #title, #header and #description are what the layers are called; the properties are Title, Header and Description. The panel now uses the property names, matching the Style tab and Property Mapping.
C2 Resolved
2.0.3 — September 2026Patch
Panel order follows the design — node 6507:74166
Title moved above Header. Design reordered the Figma property panel to match the order the three text layers actually appear in Banner. The demo panel and Property Mapping follow: hasTitle, hasDescription, Title, Header, Description. Promo is unaffected — it has no title.
Docs
2.0.2 — September 2026Patch
Text properties wired to the demo panel — node 6507:74166
The three text properties now have controls. Title, Header and Description render as text inputs on Banner and Promo, in the Figma panel's order. Typing updates the preview and the string literal in both DEV snippets.
Docs
Spec-card panels can render text inputs. SpecCard.astro branched only to a toggle or a select, so a text property had nowhere to go. A control: 'input' kind was added to the shared schema and renderer — additive, and no existing row changes behaviour.
Docs
2.0.1 — September 2026Patch
Documentation pass on the 2026 Working File — node 6507:74166
Style tab rebuilt to the content guides. Four spec sections in order, card descriptions cleared, and Layout cut to the seven canonical keys — slot and content-block dimensions came out, Padding H, Padding V, Gap and Alignment went in, derived from the frame positions.
Docs
Typography reduced to text style names. Font, size and tracking rows removed. Title and Header are Primary/Label/Large; Description is Secondary/Bold/Caption, replacing the previously documented Primary/Bold/Heading.
Docs
Colour tokens corrected. The three text roles bind to text/color-text-stronger, text/color-text-primary and text/color-text-weak, confirmed by design. The previous text/color-text-heading / -link / -body paths were unverified.
C3 Resolved
The surface row was documenting a fill that does not exist. Container paints nothing in any version — the Title and Content frames carry white fills set to hidden. Surface now reads Transparent with no token, in the spec cards and all three colours tables.
C3 Resolved
Two boolean properties were missing from the documentation. The Figma property panel exposes hasTitle (Banner) and hasDescription (Banner, Promo). Neither appears in the layer tree, so no read-only tool had surfaced them. Both are now demo-panel toggles and Property Mapping rows.
C2 Resolved
Text properties renamed to their panel names. #title, #header and #description are layer names; the properties are Title, Header and Description. Property Mapping now uses the property names and runs to seven rows.
C2 Resolved
The asset slot no longer has a demo control. ⤷ AssetSlot is a slot, so the panel drops it and each card shows the placeholder Figma ships by default.
Docs
DEV code is live. getSnippet in demos/ad-space.js rebuilds the SwiftUI and Compose snippets from the card's controls, so turning hasTitle off drops the title argument from both.
Docs
Install coordinates corrected. gcash/east-blue-ios and com.gcash.eastblue:components:1.0.0 became AY-Org/eb-ds-ios and com.eastblue.ds:ad-space:2.0.5, matching the changelog head, and an Import block was added.
Docs
The Promo usage snippet documented the wrong component. Both blocks led with EBAdCarousel, showing how to build a rail rather than how to use Promo. Rewritten as EBAdSpace. Accessibility also gained minimum tap target and dynamic type rows, and Code Connect was emptied.
Docs
The three text properties still have no demo control. SpecCard.astro renders select and toggle only, so Title, Header and Description cannot be edited from the panel. Blocked on a shared renderer change.
Docs Partial
2.0.0 — August 2026Major
Rebuilt in the 2026 Working File — node 6507:74166
Seven sizes became three versions. The banner-sm … hero-md enum is gone. The component is now Variant = Receipt | Banner | Promo on a new node in the 2026 Working File. The previous component at 18563:9789 in Sticker Sheets v2 is deprecated. Rebuilt
Family
C2 — Size renamed to Variant. The values name where the ad goes rather than how big it is, so Size is freed for its XS–XL meaning under the naming guidelines. Resolved
C2 resolved
C1 — one anatomy across all three versions. Receipt gained the Container wrapper the other two already had, and the slot was renamed ⤷ AssetSlot everywhere. Resolved
C1 resolved
C1 — text layers renamed. #label (holding "Title") became #title, and the old #title (holding "Header") became #header, in every version. Resolved
C1 resolved
isLoading and the caption removed. Neither exists on the rebuilt component. The skeleton treatment and the optional caption string documented against the old seven-size schema no longer apply. Removed
Property
C3 — token binding attested, not verified. Text colours are reported as bound to colour styles, but the read-only tools used for this assessment return raw hex without exposing bindings. Needs a Dev Mode confirmation.
C3 partial
New sibling: Ad Carousel. The rail that wraps this component is now assessed as its own page under the Ad Space group.
Family
1.0.0 — April 2026Major
Canonical consolidation — node 18563:9789
Consolidates Ads On Receipt, Ad Space - Group - Large, Dashboard Promo Cards — 3 source components (5 total with the Placeholder Banner and Promo Cards Images asset libraries) collapse into a single Ad Space with a 7-value size enum grouped into three families: banner (IAB / AdMob), promo (dashboard tile), hero (full-width). Initial
Family
C1 — Component splintering resolved — Ads On Receipt (18563:9789), Ad Space - Group - Large (18563:9808), and Dashboard Promo Cards (18563:9917) merged into one component. Legacy components marked for deletion post-adoption. Resolved
C1
C2 — hifi/midfi fidelity axis retired — Legacy type=hifi | midfi was a placeholder-authoring crutch, not a runtime variant. Replaced with an orthogonal isLoading boolean. Content flows through the content slot regardless of state. Resolved
C2
C4 — carousel=yes pseudo-variant retired — The legacy "carousel preview" variant was a static 3-card Figma layout, not a runtime carousel. Multi-ad rails are now authored by composing multiple AdSpace size="hero-md" instances inside the DS EBCarousel. Resolved
C4
C6 — Placeholder asset libraries retired — Placeholder Banner (18563:9937, 8 variants) and Promo Cards Images (18563:9928) no longer ship. Media flows through the content slot; product teams provide imagery from their own asset pipeline. Resolved
C6
C7 — 1:1 native mapping — banner-* sizes map to GADBannerView / AdView. promo-* / hero-* map to a single EBAdSpace view/composable. Clean enum, boolean, string, slot signatures ready for Code Connect CLI registration. Resolved
C7
Token namespace proposed — main/ad-space/color/surface, main/ad-space/color/caption, main/ad-space/color/loading-skeleton. Replaces ad-hoc use of generic surface tokens across the legacy trio. Initial
Tokens
Telemetry contract added — Native component exposes onImpression (50% visible ≥1s) and onTap. AdMob-backed banner-* inherits the SDK's tracking; product-owned promo-* / hero-* wire consumer analytics via the callbacks. Initial
API