RestructureRequires Rework
Banner Component link

A neutral-background promotional banner with an image or icon, a text stack (preamble, heading, description), and an optional button link.

Restructure — collapse 5 boolean-ish axes into a clean API, add asset/background slots, consolidate with Carousel - Item
Property names with spaces (with link, with button, with preamble, with icon) don't survive codegen. with link + with button describe mutually exclusive CTAs and should be one action enum. with icon is too narrow — a leading asset slot accepting Icon / Avatar / Illustration / Image is more reusable. Property = Within A Container | Full Width is a padding/layout concern owned by the parent. Background image and chevron should be vector slots. Finally, Banner and Carousel - Item share enough DNA to be one component with carousel behaviour on the container.

Banner is used in-flow as a promotional callout — typically between sections on a Home or Dashboard screen. "Within A Container" leaves horizontal padding on either side so the banner sits as a card; "Full Width" bleeds edge-to-edge. The image or icon sits on the opposite side of the text per the position axis.

Replace me
Heading
Add description here.
Properties
Property
position
with preamble
with icon
action
Reusable
Partial
Banner reads cleanly across promo, info, and up-sell contexts, but the image asset is an instance of a sibling component (not a declared slot) and the icon variant bakes in a grey placeholder — both force product teams to detach or fork to drop in real artwork.
Self-contained
Warn
Card chrome, text tokens, and colors resolve to main/banner/color/*. But the chevron on the button link is a raster shape_full PNG, and the icon placeholder is a drawn circle — neither is self-contained as a vector instance.
Consistent
Fail
Five boolean-ish axes with space-separated names (with link, with button, with preamble, with icon) — no other DS component uses spaces in property names. Property = Within A Container | Full Width is a padding concern named like a semantic mode. with link + with button are mutually exclusive but modeled as independent booleans.
Composable
Partial
Nests cleanly into Home/Dashboard scrollers and maps to iOS HStack / Compose Row. Duplicates ~95% of Carousel - Item's schema — the two should be one component.
State iOS Android Figma Property Notes
Default Yes Yes Property × position × with link × with button × with preamble × with icon Static banner; whole card is the tap target when an action is present.
Pressed N/A N/A Not built Tappable banner lacks pressed feedback — needs a subtle scale-down or overlay tint.
Focused N/A N/A Not built Keyboard / D-pad focus ring needed when used in an a11y-first flow.
Within A Container N/A N/A Property=Within A Container 12 px outer padding + 8 px corner radius around the banner card. Owned by the parent layout on native — not a component variant.
Full Width N/A N/A Property=Full Width No outer padding, no corner radius. Also owned by the parent layout.
  • Property names use spaces. with link, with button, with preamble, with icon aren't valid identifiers in any native codegen target. Should be camelCase: hasLink, hasAction, hasPreamble, hasLeadingAsset. C2 · Variant & Property Naming
  • Property is a meta-name, not a semantic one. Its values (Within A Container / Full Width) describe outer padding and corner radius — a layout concern the parent should own. Rename to padding if kept, or drop the axis entirely and let the consumer control width + padding. C2 · Variant & Property Naming
  • with link + with button encode mutually exclusive CTAs as independent booleans. Both are text + chevron link styles — the distinction is cosmetic. This schema admits the impossible state with link=yes + with button=yes (excluded by authoring convention, not by the schema). Collapse into one action enum. C2 · Variant & Property Naming
  • Sparse cartesian variant space. 5 boolean-ish axes × 2 container modes would yield 64 combinations; only 20 ship. Author manually pruned invalid combos — that logic should live in the schema (enums, mutually exclusive props), not in variant authoring discipline. C1 · Layer Structure & Naming
  • No first-class image slot. The image is an instance of a separate "Banner Asset Placeholder" component — product teams swap via instance-override rather than a declared Figma Slot. Should be a named asset slot accepting an Image, Illustration, or Gradient. C4 · Native Mappability
  • with icon=yes renders a drawn grey circle. The icon slot is a flat #C2C6CF circle, not a swappable Icon / Avatar / Illustration instance. Can't carry a token-bound color or glyph. C6 · Asset & Icon Quality
  • Chevron is a raster shape_full PNG. The "learn more" arrow ships as an <img> asset. Doesn't scale cleanly and can't take a token tint. C6 · Asset & Icon Quality
  • No pressed / focused / disabled states. The whole banner is tappable but only Default is modeled. Native platforms need pressed (tap feedback) and focused (keyboard/D-pad) at minimum. C5 · Interaction State Coverage
  • Container padding modeled as a component variant. Within A Container adds 12 px outer padding and wraps the inner card in a rounded container; Full Width drops both. On native this is a layout-level decision (parent gives Banner its width + padding), not a Figma variant. C4 · Native Mappability
  • Code Connect mappings not registered. Blocked until properties are renamed, axes are collapsed, and asset/background slots are adopted. C7 · Code Connect Linkability
  • Rename space-separated booleans to camelCase. with linkhasLink, with buttonhasAction, with preamblehasPreamble, with iconhasLeadingAsset. Matches the DS-wide naming fix applied to Carousel Item and the Form family. Rename
  • Collapse with link + with button into one action enum. action: .none | .link("Label") | .button("Label"). Mutually exclusive CTAs shouldn't be modeled as independent booleans — the schema should make with link=yes + with button=yes unrepresentable. Property
  • Replace with icon boolean with a leading asset slot. Accept an Icon, Avatar, Illustration, or Image instance. Native: leadingAsset: @ViewBuilder (SwiftUI) / leadingAsset: @Composable () -> Unit (Compose). Eliminates the rigid icon-only placeholder. Slot
  • Add a background / image slot. Replace the "Banner Asset Placeholder" instance with a first-class Figma Slot that accepts an Image, Illustration, or Gradient. Native: background: AnyView / background: @Composable () -> Unit. Slot
  • Rename Property → drop it or make it padding. Within A Container vs Full Width is a padding + radius concern owned by the parent layout on native. Either remove the axis entirely (the banner fills whatever width its parent hands it) or rename to padding: .container | .full. Property
  • Rename positionimagePosition. More specific and self-documenting. Keep as .left | .right enum. Rename
  • Consolidate with Carousel - Item. Both components have preamble / heading / description / button / image-with-position slots. The only difference is peek/snap behaviour — which belongs on the carousel container (scroll snap + scale/opacity transforms), not a sibling component. Target: one EBBanner used standalone or inside EBCarousel. Family
  • Vectorize the chevron. Swap the raster shape_full for a vector Icon instance — crisp at any scale, token-bound tint. Asset
  • Add pressed + focused states. Pressed: 0.98 scale or 6–8% overlay on tap. Focused: 2 px focus ring at border/focus. Banners are always tappable and need both feedback signals. State
  • Announce as a single actionable element. VoiceOver and TalkBack should read preamble + heading + description + action label as one announcement with a button/link role. A11y
Variants
Within A Container · with preamble
DES DEV

The most content-rich variant — preamble + heading + description + button link, with the image on the right and the content column left-aligned. Wraps in a rounded card with 12px outer padding.

Replace me
Preamble
Heading
Add description here.
Properties
Property
Position
With Preamble
With Icon
Action
Properties
Property Within A Container
Position left
With preamble yes
With icon no
Action button
Colors
Card bg #FFFFFF
Preamble #072592
Heading #072592
Description #6780A9
Action label #005CE5
Chevron tint #005CE5
Layout
Outer frame 360 × 155 (hug)
Outer padding 12 (space/space-12)
Inner card padding 16
Corner radius radius/radius-3 (8px)
Content column 216 (pl=120 for image)
Content gap 2 lines · 16 before button
Image area 360 × 152 absolute
Chevron 24 × 24
Typography
Preamble style Primary/Label/Fine
Preamble font Proxima Soft Bold · 12/12 · +0.5
Heading style Primary/Headlines/Block
Heading font Proxima Soft Bold · 18/23 · +0.25
Description style Secondary/Bold/Caption
Description font BarkAda Semibold · 12/18
Action label Secondary/Heavy/Base · 14/20
Within Container — Colors

Banner that nests inside a parent surface. Card bg is transparent; only typography roles carry color tokens.

Role Token Default
Card bg banner/color/bg transparent
Preamble banner/color/preamble #072592
Heading banner/color/heading #072592
Description banner/color/description #6780A9
Action label banner/color/action #005CE5
Chevron tint banner/color/chevron #005CE5
Full Width · with button
DES DEV

Edge-to-edge variant — no outer padding, no corner radius. The banner's own 16px padding sits directly against the screen edges. Used when the banner is the hero element of the section.

Heading
Add description here.
Replace me
Properties
Property
Position
With Preamble
With Icon
Action
Properties
Property Full Width
Position right
With preamble no
With icon no
Action button
Colors
Card bg #FFFFFF
Heading #072592
Description #6780A9
Action label #005CE5
Layout
Width × Height 360 × 119 (hug)
Outer padding 0 (full-width)
Inner padding 16
Corner radius 0
Content column 184
Image area 360 × 152 absolute
Typography
Heading style Primary/Headlines/Block
Description style Secondary/Bold/Caption
Action label Secondary/Heavy/Base
Full Width — Colors

Edge-to-edge banner with a white surface and an optional faint border tint.

Role Token Default
Card bg banner/color/bg #FFFFFF
Border banner/color/border #DFECFF
Heading banner/color/heading #072592
Description banner/color/description #6780A9
Action label banner/color/action #005CE5
Chevron tint banner/color/chevron #005CE5
Within A Container · icon · no action
DES DEV

Icon-led variant — replaces the image with a drawn grey circle placeholder. No action CTA. Used when the banner is informational rather than promotional.

Heading
Add description here.
Properties
Property
Position
With Preamble
With Icon
Action
Properties
Property Within A Container
Position left
With preamble no
With icon yes
Action none
Colors
Card bg #FFFFFF
Icon placeholder #C2C6CF
Heading #072592
Description #6780A9
Layout
Outer frame 360 × 176 (hug)
Icon 19.7 × 19.7 circle
Content column 240 (pl=119)
Gap 4 between icon and heading
Typography
Heading style Primary/Headlines/Block
Description style Secondary/Bold/Caption
With Icon — Colors

Same nested-card palette as Card 1, with a leading icon role replacing the preamble.

Role Token Default
Card bg banner/color/bg transparent
Icon tint banner/color/icon #005CE5
Heading banner/color/heading #072592
Description banner/color/description #6780A9
Action label banner/color/action #005CE5
Figma PropertySwiftUICompose
Property: Within A Container | Full Width padding: container | none (or drop) Parent layout
position: left | right imagePosition: left | right imagePosition: .left
with preamble preamble?: String preamble: String?
with link + with button action: .none | .link | .button action: EBBannerAction?
with icon leadingAsset slot leadingAsset: () -> AnyView
(Banner Asset Placeholder instance) background: Image | Illustration slot background: AnyView
(raster chevron) vector Icon Built into .link/.button action
(not modeled) onTap: () -> Void onTap: (() -> Void)?
RequirementiOSAndroid
Whole-card tap target Wrap in Button with combined accessibilityLabel (preamble + heading + description + action). Modifier.clickable().semantics(mergeDescendants = true).
Role announcement .accessibilityAddTraits(.isButton) when action is set. Role.Button inside semantics.
Decorative image .accessibilityHidden(true) on the background image view. contentDescription = null on the background Image.
Focus ring Default SwiftUI focus ring (tvOS + iPadOS keyboard nav). D-pad focus: 2 dp outline at border/focus.
Min touch target 360 × (93-176) ≫ 44 pt ✓ 360 × (93-176) ≫ 48 dp ✓

Do

Use Banner for in-flow promo / info callouts between content sections. Keep the heading to 1-2 lines.

Don't

Use both a link and a button — action is single-CTA by design.

Do

Pick imagePosition based on reading flow — LTR locales usually prefer .left image + right-aligned text.

Don't

Stack Banner inside a carousel — compose EBBanner inside EBCarousel instead.

Do

Use preamble for category context (PROMO, NEW, TIP). Let the parent layout own outer padding.

Don't

Bake text into the image — background is decorative only. Don't ship the drawn-circle icon placeholder.

ID Criterion Status Notes
C1 Layer Structure & Naming Requires Rework Sparse cartesian — 5 boolean-ish axes × 2 container modes yields 64 combos; 20 ship. Container-padding axis conflates layout with identity.
C2 Variant & Property Naming Requires Rework Property names use spaces (with link, with button, with preamble, with icon). Property is a meta-name. with link + with button encode mutually exclusive CTAs as two booleans.
C3 Token Coverage Ready All colors bind to main/banner/color/*; radii to radius/radius-3; spacing to space/space-*; bg to main/banner/color/bg.
C4 Native Mappability Requires Rework Image is an instance (not a slot); container-padding axis doesn't map to native; icon-only asset axis is rigid.
C5 Interaction State Coverage Requires Rework Only Default — no pressed, focused, or disabled for a tappable banner.
C6 Asset & Icon Quality Requires Rework Raster shape_full chevron. Drawn grey circle icon placeholder. Image asset is a separate component instance.
C7 Code Connect Linkability Not Mapped Blocked on property renames, axis collapse, and slot adoption.

Property (2) × position (2) × with link × with button × with preamble × with icon — if all boolean combinations shipped, 2 × 2 × 2 × 2 × 2 × 2 = 64 variants. The author pruned invalid combos (with link=yes + with button=yes, with icon=yes + with button=yes, etc.) and shipped 20 variants — 10 per Property mode, mirrored across position=left|right.

Content shapePropertyCountExample nodes (left · right)
heading + desc + buttonWithin A Container2756:82659 · 756:82653
heading + desc + buttonFull Width2756:82669 · 756:82667
heading + desc + icon (no action)Within A Container2756:82657 · 756:82658
heading + desc + icon (no action)Full Width2756:82668 · 756:82672
preamble + heading + desc + buttonWithin A Container2756:82655 · 756:82656
preamble + heading + desc + buttonFull Width2756:82664 · 756:82662
heading + desc + linkWithin A Container2756:82654 · 756:82671
heading + desc + linkFull Width2756:82663 · 756:82670
heading + desc (no action)Within A Container2756:82665 · 756:82666
heading + desc (no action)Full Width2756:82661 · 756:82660
Initial Assessment · node 756:82673
Verdict: Restructure — Rename space-separated booleans, collapse link/button into one action enum, add leading asset + background slots, vectorize chevron, add pressed state, consolidate with Carousel - Item. Open
Family
C1 — Sparse cartesian axes — 5 boolean-ish axes × 2 container modes = 64 combos; 20 ship. Invalid combos pruned by convention, not by schema. Open
C1
C2 — Property names with spaceswith link, with button, with preamble, with icon, and meta-named Property. Mutually exclusive CTAs modeled as independent booleans. Open
C2
C4 — Image slot + container-padding axis — Image is a sibling-component instance, not a Figma Slot. Property=Within A Container | Full Width conflates layout with identity. Open
C4
C5 — Missing interaction states — No pressed, focused, or disabled for a tappable banner. Open
C5
C6 — Raster chevron + drawn icon placeholder — Vectorize chevron; swap drawn circle for a leading asset slot. Open
C6
C7 — Code Connect — Blocked on renames, axis collapse, and slot adoption. Open
C7