A header variant with the title centered, optional leading and trailing actions on either side.
4368:12839 in the 2026 Working File as Page Banner, with Surface = Brand | Default replacing the old type = dark | light. Layer naming is now settled across both variants — Content wrapping Title and a SubtitleRow of Label and Value — which lets the title expose as a single text property and clears the legacy # prefix. The brand surface color and its alpha values are confirmed intentional, the remaining alignment difference is inert because the text node hugs its content, and an Alignment axis was decided against. All four DS Health traits pass; the only item still open is Code Connect, blocked until the native library exists.Page Banner sits at the top of a screen, modal, or feature card — centered, taking full width, setting the title of the surface below it.
Surface = Brand | Default is PascalCase per §1 with Title Case values per §5, and the text layers map onto the §3 vocabulary as Title · Label · Value, identically in both variants.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default (Brand) | Yes | Yes | Surface=Brand | White title on the brand surface. |
| Default (Default) | Yes | Yes | Surface=Default | Dark title on the default white surface. |
| Pressed | N/A | N/A | — | Banner is informational — no pressed state. |
| Disabled | N/A | N/A | — | Not interactive. |
- Renamed to Page Banner. v2.0: Rebuilt on node
4368:12839in the 2026 Working File. The name no longer sits in the Header namespace that four structurally different components were sharing, and it says what the component is — a full-width banner setting the title of the surface below it, not a navigation bar. (C1 · Rename) C1 · Layer Structure & Naming -
type = dark | lightreplaced bySurface. v2.0: The axis now readsSurface = Brand | Default, naming the surface role rather than the appearance that follows from it — the same shape Brand App Bar landed on, so the two read consistently across the family. PascalCase property per §1, Title Case values per §5. (C2 · Rename) C2 · Variant & Property Naming - Layer names settled across both variants. v2.1: Verified on the live node.
header→Content; the 22px title, previously#namein Brand and#labelin Default, is nowTitlein both;text-container→SubtitleRow, holdingLabelandValue. Three problems closed at once: the cross-variant mismatch that stopped the title exposing as a single text property, the duplicate#labelinside the Default variant, and the legacy#prefix. Names now follow the §3 vocabulary. (C1 · Rename) C1 · Layer Structure & Naming - Brand surface color and its alpha values confirmed intentional. v2.1: The brand fill
#1972F9differs from Brand App Bar’s#005CE5, and the brand sub-row key and border are#F6F9FDat 72% and 24%. Confirmed by the owner as bound to generic tokens and deliberate rather than local overrides — the two surfaces serve different jobs, and a banner sitting above content is not required to match the app bar’s blue. Attested rather than verified: variable bindings and opacity tokens are not readable through the review tooling, so this is recorded on the owner’s confirmation. (C3 · Token) C3 · Token Coverage - Sub-row alignment difference is inert. v2.1: The sub-row key still reads
LEFTon Brand andCENTERon Default, but the text node hugs its content — 36px wide for “Label:” inside a 119px row — so horizontal alignment inside it has nothing to distribute and produces no visual difference on either surface. A leftover value rather than a behavioural one, and nothing a native implementation has to reproduce. (C4) C4 · Native Mappability - No
Alignmentproperty. v2.1: Decided against. A centered banner is what the component is for; a left-aligned title is a different component’s job, and adding the axis would double the set to serve a case nobody has asked for. Closed rather than carried forward a third time. (Property) C2 · Variant & Property Naming - Sub-row composition confirmed as intended. v2.1: The
SubtitleRowis present in both live variants; the owner confirms the current composition is the intended one, closing the question left over from the olddescription = yes | nocontrol. Attested rather than verified — component property definitions are not readable through the review tooling. (Docs) C2 · Variant & Property Naming - Place in the header family settled. v2.1: Page Banner is confirmed a distinct component, not a variant of another. It sets the title of the surface below it; Section Header labels a section inside a scroll, Brand App Bar carries the wordmark, and Title Bar - App carries navigation. Four different jobs, four components, none folding into another. Siblings: Section Header · Brand App Bar · Detail Hero. (Family) C4 · Native Mappability
| Role | Element | Token | Value |
|---|---|---|---|
| Brand | Surface | — | #1972F9 |
| Brand | Bottom border | — | #F6F9FD @ 24% |
| Brand | Title | — | #FFFFFF |
| Brand | Label | — | #F6F9FD @ 72% |
| Brand | Value | — | #FFFFFF |
| Default | Surface | — | #FFFFFF |
| Default | Bottom border | — | #E5EBF4 |
| Default | Title | — | #0A2757 |
| Default | Label | — | #6780A9 |
| Default | Value | — | #0A2757 |
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:header:1.0.0")
Import
import EastBlueDS import com.eastblue.ds.header.*
Surface is the set’s only variant property. Title, Label and Value are text layers read from 4368:12846 — their exposure as text properties is not readable with the plugin.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| Surface — Brand, Default | .ebSurface(.brand / .default) | surface = EBBannerSurface.Brand / Default |
| Title (text) | title: String | title = "…" |
| Label (text) | label: String | label = "…" |
| Value (text) | value: String | value = "…" |
EBPageBanner(
title: "Label",
label: "Label:",
value: "Add Content"
)
.ebSurface(.brand) EBPageBanner(
title = "Label",
label = "Label:",
value = "Add Content",
surface = EBBannerSurface.Brand
) EBPageBanner(
title: "Label",
label: "Label:",
value: "Add Content"
)
.ebSurface(.default) EBPageBanner(
title = "Label",
label = "Label:",
value = "Add Content",
surface = EBBannerSurface.Default
) | Requirement | iOS | Android |
|---|---|---|
| Heading | Title carries .accessibilityAddTraits(.isHeader). | Modifier.semantics { heading() } on the title. |
| Label and value read together | .accessibilityElement(children: .combine) on the SubtitleRow. | Modifier.semantics(mergeDescendants = true) on the row. |
| Contrast | White title on #1972F9 is 4.0:1; the 72% label is decorative-weight. | Same values — the surfaces are fixed, not themed. |
| Status bar | Brand needs .preferredColorScheme(.dark) for the status bar. | isAppearanceLightStatusBars false on Brand. |
Do
Use Brand at the top of a section screen; Default when the banner sits under a Brand app bar.
Don't
Don’t stack Brand under Brand — two blues merge.
Do
Keep the Title to one line; 26 px line-height is sized for one.
Don't
Don’t put a sentence in the title — the subtitle row carries the fact.
Do
Use the Label / Value pair for the one figure the page is about.
Don't
Don’t add a second subtitle row — the set builds one.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | Content › Title / SubtitleRow › Label / Value — read on 4368:12846. |
| C2 | Variant & Property Naming | Ready | Surface — Brand, Default; the type axis is gone. |
| C3 | Token Coverage | Ready | Title → Primary/Headlines/Section, Label and Value → Secondary/Bold/Base. Colour variable bindings are not readable with the plugin — confirm in Dev Mode. |
| C4 | Native Mappability | Ready | One enum and three strings — maps 1:1 onto EBPageBanner. |
| C5 | Interaction State Coverage | Not Applicable | Static banner with no tap target. |
| C6 | Asset & Icon Quality | Not Applicable | No icons or images. |
1 Surface × 2 values = 2 variants
| Surface | Node | Dimensions |
|---|---|---|
| Brand | 4368:12840 | 360 × 104 |
| Default | 4368:12846 | 360 × 104 |
Surface value; geometry, colours and the three text styles verified on 4368:12840 and 4368:12846 against the exports. Padding, gap, alignment and colour tokens are not readable with the plugin and stay —.Surface schema. Property Mapping one row per property, Usage Snippets per Surface, Guidelines added, Scorecard regraded from the type era, Variants Inventory on the two live nodes.type = dark | light replaced by Surface; Layer names settled across both variants; Brand surface color and its alpha values confirmed intentional; Sub-row alignment difference is inert; No Alignment property; Sub-row composition confirmed as intended; Place in the header family settled.type=dark|light for surface=brand|default. Open