KeepReady
Ad Space Component link

A canonical surface for ads, promos, and sponsored placements — supports banner, promo, and hero size families with a single content slot.

In Context

Each of the three size families has a canonical home in the app: banners inline within transaction flows, promos on the dashboard tile grid, and heroes full-width on home or category surfaces.

Live Preview
Replace me · 224×200
Offer title
Properties
size
isLoading
Content
caption
DS Health
Reusable
Pass
One component serves every ad placement across the app: inline receipt banners, dashboard tiles, and full-width heroes. Seven canonical sizes cover IAB-standard banners plus product surfaces.
Self-contained
Pass
Ships its own surface, caption typography, loading skeleton, and corner radius tokens. Media flows through the content slot — no hardcoded rasters, no placeholder "replace me" assets.
Consistent
Pass
Size naming follows a predictable pattern: <family>-<size>. Content and state are orthogonal axes. Caption typography uses the same DS text style across all promo and hero sizes.
Composable
Pass
Plugs into the DS Carousel for multi-ad layouts (e.g. a row of hero-md), into list rows for inline banners, and into the dashboard grid for promo tiles. No sibling "Ad Carousel" or "Ad Group" needed.
Behavior
State iOS Android Figma Property Notes
banner-sm N/A N/A GADBannerView AdView
banner-lg N/A N/A GADBannerView AdView
banner-mrec N/A N/A GADBannerView AdView
promo-sm N/A N/A custom EBAdSpace custom composable
promo-md N/A N/A custom EBAdSpace custom composable
hero-sm N/A N/A custom EBAdSpace custom composable
hero-md N/A N/A custom EBAdSpace custom composable
isLoading N/A N/A RedactedShape shimmer composable
Design Recommendations
  • Adoption — deprecate and delete the three legacy components. Swap all Figma usages of Ads On Receipt, Ad Space - Group - Large, and Dashboard Promo Cards to Ad Space with the matching size. Delete the old components plus the Placeholder Banner and Promo Cards Images asset libraries once zero-usage is confirmed. Family
  • Asset pipeline — ship promo and hero imagery as product assets, not DS assets. Product teams export 1×/2×/3× image assets from their marketing pipeline and pass them into the content slot. The DS ships the container, typography, radius, and skeleton only — no imagery. This is what retires the 8-variant Placeholder Banner and 6-variant Promo Cards Images asset sets. Asset
  • Carousel composition — no "Ad Carousel" component. Multi-ad rails (e.g. a horizontal row of hero-md) are authored as <Carousel><AdSpace size="hero-md" /><AdSpace size="hero-md" />…</Carousel>. The old carousel=yes pseudo-variant is retired because it was a static 3-card Figma preview, not a runtime carousel. Document this composition pattern in the Carousel and Ad Space guidelines. Composition
  • Tokens — propose a main/ad-space/color/* namespace. Ship main/ad-space/color/surface (card background), main/ad-space/color/caption (caption text), and main/ad-space/color/loading-skeleton (shimmer fill). Today the legacy components reuse generic bg/color-bg-main and bg/color-bg-strong; a dedicated namespace makes cross-family theming (dark mode, partner-branded surfaces) tractable. Token
  • Telemetry — bake impression and tap tracking into the native component. The iOS EBAdSpace view and Android composable should emit onImpression (50% visible for ≥1s) and onTap callbacks. AdMob-backed banner-* sizes get this for free; promo-* and hero-* need product-side reporting. Document the contract in the Code tab so consumer teams wire analytics consistently. Docs
  • A11y — treat ads as labeled buttons, not decorative images. Every Ad Space is tappable and leads somewhere; the whole surface must expose a single accessibility label (caption + "Advertisement" trait). Banner family should announce "Advertisement" as its accessibility hint per App Store / Play Store disclosure norms. A11y
  • Caption — optional, typography-constrained, never mandatory. Promo and hero families accept an optional caption string; banner family has none (AdMob renders its own chrome). Caption uses Secondary/Bold/Caption — one line for promo-sm, up to two lines for promo-md / hero-*. Empty caption hides the label slot; it does not reserve space. Slot
  • See siblings: Carousel Card and the broader Carousel family — Ad Space heroes wrap inside the DS Carousel; keep skeleton treatment aligned across card primitives. Family
Size families
Banner family
DES DEV

IAB-standard banner sizes driven by AdMob. The DS provides a fixed-dimension surface; the ad SDK renders the creative in the content slot.

Ad320×50
Properties
Size
isLoading
Properties
Size family banner
Size banner-sm
isLoading false
Content slot AdMob view
Colors
Surface #FFFFFF
Loading skeleton #EEF2F9
"Ad" marker #6780A9
Layout
Dimensions 320 × 50
Corner radius radius/radius-1 (4px)
Padding 0 (ad fills surface)
Typography
"Ad" marker style Secondary/Bold/Caption
Font BarkAda Semibold · 10 / 14 · +0.25
Banner — Colors

Surface tile that hosts the ad creative. Skeleton + label colors are the only DS-owned tokens.

Role Token Default
Surface ad-space/color/surface #FFFFFF
Loading skeleton ad-space/color/loading-skeleton #EEF2F9
"Ad" marker text/color-text-subtle #6780A9
Promo family
DES DEV

Product-owned dashboard tiles. Image fills the upper portion; an optional caption sits beneath.

Replace me · 224×200
Earn up to 5% on savings
Properties
Size
isLoading
Properties
Size family promo
Size promo-md
isLoading false
Content slot Image or illustration
Caption prop caption: String?
Colors
Surface #FFFFFF
Caption #2340A9
Image placeholder #E6E1EF
Layout
Dimensions 224 × 200
Image aspect 3:2
Corner radius radius/radius-2 (8px)
Caption padding 8 horizontal, 6 vertical
Typography
Caption style Secondary/Bold/Caption
Font BarkAda Semibold · 12 / 16
Max lines 1 (sm) · 2 (md)
Promo — Colors

Same DS-owned palette as the Banner; promo creative fills the surface.

Role Token Default
Surface ad-space/color/surface #FFFFFF
Loading skeleton ad-space/color/loading-skeleton #EEF2F9
"Ad" marker text/color-text-subtle #6780A9
Hero family
DES DEV

Full-width hero banners for home and category surfaces. <code>hero-md</code> is the canonical item inside a DS Carousel for multi-ad rails.

Replace me · 336×174
Weekend deals are here
Properties
Size
isLoading
Properties
Size family hero
Size hero-md
isLoading false
Content slot Image or illustration
Carousel DS Carousel for multi-ad rails
Colors
Surface #FFFFFF
Caption (overlay) #FFFFFF
Caption scrim #040506
Image placeholder #E6E1EF
Layout
Dimensions 336 × 174
Image aspect 15:8
Corner radius radius/radius-3 (12px)
Caption padding 12 horizontal, 8 vertical
Typography
Caption style Primary/Headlines/Block
Font Proxima Soft Bold · 16 / 20 · +0.25
Max lines 2
Position Overlay on lower third
Hero — Colors

Same DS-owned palette as the Banner; hero creative fills the larger surface.

Role Token Default
Surface ad-space/color/surface #FFFFFF
Loading skeleton ad-space/color/loading-skeleton #EEF2F9
"Ad" marker text/color-text-subtle #6780A9
Property Mapping
Figma PropertySwiftUICompose
size: banner-sm | banner-lg | banner-mrec | promo-sm | promo-md | hero-sm | hero-md size: EBAdSpaceSize size: EBAdSpaceSize
isLoading: Boolean isLoading: Bool isLoading: Boolean
content: Frame (slot) content: () -> AnyView content: @Composable () -> Unit
caption: String? caption: String? caption: String?
(not modeled) onImpression: (() -> Void)? onImpression: (() -> Unit)?
(not modeled) onTap: (() -> Void)? onClick: (() -> Unit)?
Accessibility
RequirementiOSAndroid
Ad disclosure Add .accessibilityHint("Advertisement") so VoiceOver announces the trait alongside the caption. Set Modifier.semantics { contentDescription = "Advertisement, ${caption}" }.
Ad as a single button Whole surface wrapped in Button { onTap() } with accessibilityElement(children: .combine). Modifier.clickable { onClick() }.semantics(mergeDescendants = true).
Image alt Banner content is decorative from a11y's perspective — caption carries the meaning. contentDescription = null on the inner image; caption carries meaning.
Min touch target All seven sizes exceed 44 pt height ✓ All seven sizes exceed 48 dp height ✓
Loading state accessibilityLabel("Loading advertisement") on the skeleton; suppress individual shimmer announcements. contentDescription = "Loading advertisement" on the skeleton container.
Focus ring .focused() → 2 px outline using border/focus token for iPad keyboard nav. Modifier.focusable() + border in border/focus.
AdMob compliance Google Mobile Ads SDK handles its own a11y metadata for banner-* — do not override. Google Mobile Ads SDK handles its own a11y metadata for banner-* — do not override.
Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready Single Ad Space component, semantic frame naming (surface, content, caption). No legacy "Group"/"Large"/"hifi"/"midfi" baggage.
C2 Variant & Property Naming Ready One size enum, one isLoading boolean, one caption string. Content and state axes are orthogonal.
C3 Token Coverage Ready Proposes a main/ad-space/color/* namespace (surface, caption, loading-skeleton) plus radius/radius-1|2|3 per family. All typography bound to DS text styles.
C4 Native Mappability Ready banner-* maps 1:1 to GADBannerView / AdView. promo-* / hero-* map to EBAdSpace (ZStack/Box image + optional caption). Carousel composition reuses EBCarousel.
C5 Interaction State Coverage Ready Default, pressed, focused, disabled, and loading states all modeled. Loading is an orthogonal boolean, not a variant.
C6 Asset & Icon Quality Ready No DS-side assets. Content flows through the slot; placeholder libraries are retired.
C7 Code Connect Linkability Ready Clean single-component mapping: EBAdSpace with enum size, boolean isLoading, slot content, string caption. 1:1 param mapping to both platforms.
Code Connect
Aspect Status Notes
Property naming Ready Clean: size (7), isLoading (bool), caption (string), content (slot).
Token coverage Ready main/ad-space/color/* namespace proposed; all colors and radii bound.
State coverage Ready Default + loading modeled; pressed/focused handled at the native layer.
Native component file Needs Refinement EBAdSpace.swift / EBAdSpace.kt not yet published — Planned API.
AdMob SDK wiring Ready Google Mobile Ads SPM + Gradle dependencies documented in Installation.
Variants Inventory (7 total)

One size enum with 7 values across 3 size families. isLoading is an orthogonal boolean, not a variant (would otherwise double the count to 14). caption is optional input, not a variant.

FamilySize valueDimensionsAspectCorner radiusContent slot
bannerbanner-sm320 × 5032:54AdMob · IAB Mobile Banner
bannerbanner-lg320 × 10016:54AdMob · IAB Large Banner
bannerbanner-mrec300 × 2506:54AdMob · IAB MREC
promopromo-sm131 × 1264:3 (image)8Image + 1-line caption
promopromo-md224 × 2003:2 (image)8Image + up to 2-line caption
herohero-sm296 × 17417:1012Image + optional caption overlay
herohero-md336 × 17415:812Image + caption; default Carousel item
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 mappingbanner-* 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 proposedmain/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