The top-of-screen app bar, with status bar, title row, optional leading and trailing icons, and an optional expanded title block over an image background.
Contexts are illustrative. Final screens will reference actual GCash patterns.
has verb prefixes and genuine True/False boolean values, the leading-control dependency is explicit, and every layer this component owns is semantically named. hasTitleBlock remaining a boolean rather than a layout Variant is a documented, deliberate exception made for authoring usability.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default | Yes | Yes | 5 boolean properties | Navigation bar. No interaction states beyond tap targets on icons and control text. |
- Code Connect mappings not registered. Blocked — no native library exists yet. C7 · Code Connect Linkability
- Trailing icon placeholder replaced with a real instance. v2.0: Rebuilt on node
4784:34355in the 2026 Working File as Title Bar - App. The placeholder RECTANGLE is gone — the trailing element is now aniconinstance wrapping atrailing-iconfrom the library. (C6 · Asset) C6 · Asset & Icon Quality - Boolean values normalised to True/False. v2.1: All four properties —
hasLeadingIcon,hasTrailingElement,hasSubtext,hasTitleBlock— carry the correcthasverb prefix per §2 and now renderTrue/Falsecapitalised, confirming they are genuine Figma booleans rather than string variants. They map directly to SwiftBooland KotlinBoolean. (C2 · Rename) C2 · Variant & Property Naming - Leading control dependency made explicit. v2.0:
hasLeadingIconexposes the back/close affordance as a property rather than leaving consumers to infer it from the layout. (C2) C2 · Variant & Property Naming - Spacer instances removed from layout. v2.2: The two
_space_12spacer instances inside the title row are gone, replaced by auto-layout gap. Spacer components have no native equivalent — both platforms express this as layout spacing — and these rendered in bright#0500FF, so they would have shipped as visible artifacts. (C4) C4 · Native Mappability - Layer naming cleaned up. v2.2:
Title Bar→TitleBar(space removed),title→TextContainer,title-block→TitleBlock, and both#titletext layers →Title. (C1) C1 · Layer Structure & Naming - Two
Titlelayers confirmed intentional. v2.2: Closed by owner decision — the 16px title inTitleBarand the 26px title inTitleBlockshare the name deliberately. They sit in separate branches and represent the same content role at two scales, so a single name is the honest description. (C1) C1 · Layer Structure & Naming - Dark / transparent variant ruled out. v2.2: Closed by owner decision — no dark or transparent variant is planned. The component ships on the brand surface only, so a Theme axis would add variants describing a treatment that is never used. (Family) C3 · Token Coverage
- Background layer renamed. v2.3:
image-placeholder→Backgroundacross the expanded variants. The name now describes the role rather than implying scaffolding — it is a real background layer carrying the brand fill plus a 5% luminosity image. (C1) C1 · Layer Structure & Naming - Layer naming complete. v2.4:
icon→TrailingIcon, pairing withLeading Iconopposite it. Every layer this component owns now carries a semantic name —Background,Status Bar,TitleBarwithLeading Icon/TextContainer/TrailingIcon, andTitleBlock. The remaining hash-prefixed and kebab names (#time,trailing-icon) belong to nested library instances, not to this component. (C1) C1 · Layer Structure & Naming -
hasTitleBlockkept as a boolean by design. v2.4: Closed by owner decision — the property stays a boolean rather than becoming aVariantaxis, for authoring usability: keeping one axis means designers do not have to reposition theBackgroundimage when toggling the title block on and off. The guidelines reservehas*for content presence rather than layout modes, so this is a documented exception rather than conformance. Worth revisiting only if the two forms diverge further than background fill and height. (C2) C2 · Variant & Property Naming - Status bar documented as illustrative. v2.5: Documented rather than deferred. The
Status Bar - IOSinstance embedded in every variant — SF Pro clock, iOS battery glyph, cellular and wifi indicators — is mock fidelity only. Neither platform lets an app draw its own status bar: iOS and Android render it from system state, and an app controls only its appearance (light or dark content, and on Android the background behind it). Implementers should build the title row and treat the 44px above it as safe-area inset, not as anatomy to reproduce. That is also why noPlatformaxis is needed — the component would look identical on Android in every respect the app actually controls. (C4 · Docs) C4 · Native Mappability
Standard title bar without title block. Status bar (44px) + title row with optional icons, control, and subtext. Height ranges from 84px to 100px depending on subtext.
Single color scheme -- no appearance modes. All colors bound to main/title-bar/color/ tokens. Display/navigation component with no state-driven color changes.
| Role | Token | Value |
|---|---|---|
| Background | main/title-bar/color/bg | #1972F9 |
| Title label | main/title-bar/color/label-title | #FFFFFF |
| Header label | main/title-bar/color/label-header | #FFFFFF |
| Subtext / URL | main/title-bar/color/label-url | #F6F9FDCC (80% opacity) |
| CTA text | main/title-bar/color/label-cta | #FFFFFF |
| Icon | main/title-bar/color/icon | #FFFFFF |
Title bar with expanded header block (72px) below the title row. Used for screens with prominent section headers. Adds "Header" text at 26px Semibold.
| Role | Token |
|---|---|
| Status bar height | 44px |
| Title row padding H | 20px |
| Title row padding V | 12px |
| Leading icon size | 24 x 24 |
| Trailing icon size | 24 x 24 |
| Title block height | 72px |
| Title block padding H | 24px |
| Total height (no subtext, no block) | ~84px |
| Total height (with subtext, no block) | ~100px |
| Total height (with block) | ~156--172px |
iOS -- Swift Package Manager
// In Xcode: File -> Add Package Dependencies "https://github.com/AY-Org/eb-ds-ios"
Android -- Gradle (Kotlin DSL)
dependencies { implementation("com.eastblue.ds:titlebar:1.0.0") }
Import
import EastBlueDS // SwiftUI import com.eastblue.ds.titlebar.* // Compose
Package not yet published. These are the planned distribution paths.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| leading icon (yes/no) | .ebLeadingIcon(Image?) | leadingIcon: @Composable (() -> Unit)? |
| trailing icon (yes/no) | .ebTrailingIcon(Image?) | trailingIcon: @Composable (() -> Unit)? |
| leading control (yes/no) | .ebLeadingControl("Done") | leadingControlText: String? |
| subtext (yes/no) | .ebSubtext("m.gcash.com") | subtext: String? |
| title block (yes/no) | .ebTitleBlock("Header") | titleBlock: String? |
EBTitleBar("Send Money")
EBTitleBar( title = "Send Money" )
EBTitleBar("Send Money") .ebLeadingIcon(Image(systemName: "arrow.left"))
EBTitleBar( title = "Send Money", leadingIcon = { Icon(Icons.Default.ArrowBack, "Back") } )
EBTitleBar("GCash") .ebLeadingIcon(Image(systemName: "arrow.left")) .ebTrailingIcon(Image(systemName: "ellipsis")) .ebSubtext("m.gcash.com") .ebTitleBlock("My Wallet")
EBTitleBar( title = "GCash", leadingIcon = { Icon(Icons.Default.ArrowBack, "Back") }, trailingIcon = { Icon(Icons.Default.MoreVert, "More") }, subtext = "m.gcash.com", titleBlock = "My Wallet" )
EBTitleBar("Edit Profile") .ebLeadingIcon(Image(systemName: "arrow.left")) .ebLeadingControl("Done")
EBTitleBar( title = "Edit Profile", leadingIcon = { Icon(Icons.Default.ArrowBack, "Back") }, leadingControlText = "Done" )
| Requirement | iOS | Android |
|---|---|---|
| Minimum touch target | 44 x 44 pt (icons and control) | 48 x 48 dp (icons and control) |
| Back button label | .accessibilityLabel("Back") | contentDescription = "Navigate back" |
| Trailing icon label | .accessibilityLabel("More options") | contentDescription = "More options" |
| Heading semantics | .accessibilityAddTraits(.isHeader) on title | semantics { heading() } on title |
Do
Use EBTitleBar as the top-level navigation element on every screen. Keep the title short and descriptive.
Don't
Nest a title bar inside scrollable content or use it as a section header within a page -- use a section heading component instead.
Do
Use the title block for high-level section headers like "My Wallet" or "Dashboard" where the large text reinforces the current context.
Don't
Show both trailing icon and leading control simultaneously -- they occupy the same trailing slot. Use one or the other.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | Semantic layer names: title, Title Bar, title-block, Leading Icon, Placeholder. |
| C2 | Variant & Property Naming | Needs Refinement | All 5 boolean properties use yes/no instead of true/false. leading control has implicit dependency on other properties. |
| C3 | Token Coverage | Ready | All 6 color roles bound to main/title-bar/color/ tokens. |
| C4 | Native Mappability | Ready | Maps to NavigationBar (iOS) / TopAppBar (Android, Material 3). |
| C5 | Interaction State Coverage | Ready | Navigation bar -- no interaction states needed beyond individual tap targets on icons and control. |
| C6 | Asset & Icon Quality | Needs Refinement | Trailing icon uses icon-placeholder RECTANGLE instead of a swappable icon instance. |
| C7 | Code Connect Linkability | Needs Refinement | No CLI mappings registered yet. |
| Aspect | Status | Notes |
|---|---|---|
| Property naming | Needs Refinement | All booleans use yes/no -- must be renamed to true/false before Code Connect mapping |
| Asset quality | Needs Refinement | Trailing icon placeholder RECTANGLE needs replacement with icon instance |
| State coverage | Ready | Navigation bar -- no interaction states needed |
| Native component file | Needs Refinement | EBTitleBar.swift / EBTitleBar.kt not yet created |
5 boolean properties (leading icon, trailing icon, leading control, subtext, title block) with implicit constraints yield 20 variants: 10 without title block + 10 with title block.
| title block | Combinations covered | Count |
|---|---|---|
| no | 10 combos of leading/trailing icon + leading control + subtext | 10 |
| yes | Same 10 combos with title block enabled | 10 |
main/title-bar/color/ tokens.
Documentedleading icon, trailing icon, leading control, subtext, title block) use yes/no instead of true/false. Incompatible with Swift Bool and Kotlin Boolean for Code Connect mapping.
Openicon-placeholder is a 24x24 RECTANGLE instead of a swappable icon instance from the DS icon library. Blocks native icon slot mapping.
Open