A transaction-detail header with the merchant logo, transaction amount, and date.
Detail Hero appears at the top of transaction detail screens and recipient profile cards — introducing the person or transaction below the app bar.
Add Label Here
Add description here.
Add description here.
email boolean can't extend to other metadata rows (phone, MCC, reference number). Needs a flexible rows slot.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default (no email) | Yes | Yes | email=no | Avatar + title + divider + description. |
| With email | Yes | Yes | email=yes | Adds an inline email: value row above the description. |
| Pressed / Disabled | N/A | N/A | — | Static — no interactive states. |
- Misfiled as a header. Anatomy is a card hero (avatar + title + divider + label-value + description). Rename to Detail Hero and move out of the Header family. C1 · Layer Structure & Naming
- Avatar is a placeholder, not an instance. Should accept a real Avatar instance (status ring, initials, image — all of which Avatar already supports). C4 · Native Mappability
- Label-value row is hardcoded to "email:". A detail hero needs flexible metadata rows (phone, reference #, MCC, transaction ID). Replace the boolean with a rows slot or accept a Labeled Field instance. C2 · Variant & Property Naming
- Pressed state on avatar is not defined — if the avatar is tappable (opens profile, edits photo), it needs state coverage. C5 · Interaction State Coverage
- No Code Connect mapping. Blocked on the Detail Hero rehome decision. C7 · Code Connect Linkability
- Rename to Detail Hero and move out of the Header family. Rehome next to Visual Popup / card primitives. Rename
- Replace the avatar placeholder with a real Avatar instance. Avatar already supports image, initials, and status ring — no reason to re-draw it here. Composition
- Replace
email=yes|nowith a flexible rows slot.metadata: [LabelValuePair]lets consumers supply any number of rows (email, phone, reference, MCC). Each row could be a small inline-label component or a Labeled Field variant. Property - Expose
surface = brand | default(same pattern as Page Banner). Detail heroes on settings screens may want the default surface. Property - See siblings: Header, Header - Centered, Header - With Logo. Family
The minimal variant — avatar + title + divider + description. Used when the profile/transaction has no extra metadata to show.
Add Label Here
Add description here.
Add description here.
Transaction-screen header on brand surface, with avatar + title + description split by a divider.
| Role | Token | Default |
|---|---|---|
| Surface bg | main/header-transaction/bg | #1972F9 |
| Title | main/header-transaction/title | #FFFFFF |
| Description | main/header-transaction/description | #FFFFFF @ 80% |
| Divider | main/header-transaction/divider | #FFFFFF @ 24% |
Adds an inline <code>email: value</code> row between the divider and the description. Used on recipient profile cards.
Add Label Here
Add description here.
Add description here.
Same brand surface as Card 1 plus a sender-details cluster (name + email) above the description.
| Role | Token | Default |
|---|---|---|
| Surface bg | main/header-transaction/bg | #1972F9 |
| Title | main/header-transaction/title | #FFFFFF |
| Sender label | main/header-transaction/sender | #FFFFFF |
| Sender email | main/header-transaction/email | #FFFFFF @ 80% |
| Description | main/header-transaction/description | #FFFFFF @ 80% |
| Divider | main/header-transaction/divider | #FFFFFF @ 24% |
| Figma Property | SwiftUI | Compose |
|---|---|---|
| (implicit) | title: String | title: String |
| (placeholder) | avatar: Avatar (instance) | avatar: EBAvatar |
email: boolean | metadata: [LabelValuePair] | metadata: [EBLabelValue] |
| (implicit) | description?: String | description: String? |
| (implicit brand) | surface: brand | default | .ebSurface(.brand) modifier |
| Requirement | iOS | Android |
|---|---|---|
| Heading trait | Apply to the title line. | Modifier.semantics { heading() } on the title. |
| Avatar a11y | If decorative, mark .accessibilityHidden(true). If identifying, label with person's name. | Same — contentDescription empty when decorative, or person's name when identifying. |
| Label-value pairs | Group each pair with .accessibilityElement(children: .combine) so VoiceOver reads "email, juan@gmail.com" as one utterance. | Use Modifier.semantics(mergeDescendants = true) per row. |
| Contrast on brand surface | White text on #005CE5 = 8.5:1 ✓. Muted #C8D8F5 on #005CE5 = 2.1:1 — fails AA body text. Use only for secondary labels ≥14pt bold. | Same ratios — reserve muted color for label text, not body copy. |
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Requires Rework | "Header - Transaction" misfiled. Rename to Detail Hero. |
| C2 | Variant & Property Naming | Requires Rework | email=yes|no should become metadata: [LabelValuePair]. |
| C3 | Token Coverage | Ready | Surface, title, description tokens bound. |
| C4 | Native Mappability | Requires Rework | Avatar should be a real instance; metadata should be structured, not drawn. |
| C5 | Interaction State Coverage | Needs Refinement | Avatar pressed state not defined — needed if tappable. |
| C6 | Asset & Icon Quality | Needs Refinement | Avatar is a drawn placeholder, not a vector Avatar instance. |
| C7 | Code Connect Linkability | Not Mapped | Blocked on rehome + avatar-instance decisions. |
| # | Node | Dimensions | |
|---|---|---|---|
| 1 | 18430:2906 | no | 360 × 220 |
| 2 | 18430:2898 | yes | 360 × 191 |
email=yes|no with a flexible metadata: [LabelValuePair] slot. Open