A section-level heading row with preamble, title, counter, description, and optional leading and trailing media.
4363:11467 in the 2026 Working File and renamed to Section Header. The 8-boolean matrix collapsed to TrailingMedia (4) × hasLeadingMedia (2) = 8 variants; property and layer naming follow the guidelines throughout, with text layers mapping onto §7 hierarchy as Preamble → Title → Description; and both media containers are now real Figma Slots. The nested Counter is the shared component as published, and the row is a static section label so interaction states are deliberately out of scope. All four DS Health traits pass; the only item still open is Code Connect, blocked until the native library exists.Section headers sit above grouped content — a list of transactions, a set of services, a carousel of offers — to label the section and optionally expose a trailing action.
TrailingMedia (4) × hasLeadingMedia (2) gives 8 variants with no invalid combinations — every one is a shape a real section actually takes.TrailingMedia is PascalCase per §1, hasLeadingMedia uses True | False per §5, and the text layers map onto §7 hierarchy — Preamble → Title → Description.Image-Slot and the trailing icon an Icon-Slot, both real Figma Slots; Trailing Media is an instance in every variant that has one; and the count comes from the shared Counter component rather than being drawn in place.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default | Yes | Yes | 16 variants | The only state today — no pressed/disabled/focused. |
| Trailing action pressed | N/A | N/A | Not modeled | Link, edit, counter should be real Button/Link instances that carry their own pressed state. |
| Disabled | N/A | N/A | Not modeled | Section headers are informational — no disabled variant needed. |
| Focused (a11y) | N/A | N/A | — | Focus lives on the trailing action, not the header itself. |
- Renamed to Section Header. v2.0: Rebuilt on node
4363:11467in the 2026 Working File and renamed fromHeaderto Section Header, describing what it actually is — a section-level heading row, not a screen chrome bar. Frees the Header prefix that four structurally different components were sharing. (C1 · Rename) C1 · Layer Structure & Naming - Eight boolean props collapsed to two. v2.0: The 8-boolean matrix with 256 theoretical combinations and 16 built variants is now
TrailingMedia(4) ×hasLeadingMedia(2) = 8 variants. Fewer than the three props recommended, and every combination is meaningful. (C2 · Property) C2 · Variant & Property Naming - Property naming corrected. v2.1:
hasTrailingMedia→TrailingMedia— a four-value enum should not carry a booleanhasprefix (§2) — andhasLeadingMediavalues wentYes | No→True | False, which §5 lists explicitly under DON'T. Thehasprefix is correct on that one because it is a genuine boolean. (C2 · Rename) C2 · Variant & Property Naming - Layer naming completed. v2.1–v2.2: Two frames both named
containerbecameLeadingMediaandHeaderContent;#title→Preamble,#heading→Title,#description→Description,header-description→DescriptionRow,header-counter→CounterSlot. The component-name prefixes are gone per §6, and the text layers now map exactly onto §7 content hierarchy:Preamble → Title → Description. Verified across all eight variants by full text scan. (C1) C1 · Layer Structure & Naming - Media containers converted to real Figma Slots. v2.2: Leading media went from a
Placeholderinstance to anImage-SlotSLOTin all fourhasLeadingMedia=Truevariants, and the trailing icon is now anIcon-SlotSLOTinside theTrailing Mediainstance. Teams can drop in real content without detaching. (C6 · Slot) C6 · Asset & Icon Quality - Trailing media made consistent across variants. v2.2:
Trailing Mediais an INSTANCE in every variant that has one — the Icon variants previously used a plain FRAME — and the stray instance inTrailingMedia=None, hasLeadingMedia=Trueis gone, so both None variants now match. (C1) C1 · Layer Structure & Naming - Nested
Counterconfirmed correct. v2.2: Closed by owner decision — theCounterinstance points at the Counter component as published, and stays. The rebuilt copy at4675:21497is a working-file version rather than a replacement, so no swap is needed. Worth revisiting only if the two ever diverge in the published library. (C4 · Composition) C4 · Native Mappability - Interaction states ruled out of scope. v2.2: Closed by owner decision — Section Header is not tappable. It is a static section label, so
Default | Pressed | Disabledwould describe interactions the component never has. Any tap target lives in the trailing media, and its states belong to that component. (C5) C5 · Interaction State Coverage - Header-family restructure closed. v2.3: Closed for this component. The restructure that mattered here is done — the base component is Section Header, which frees the Header prefix that four structurally different components were sharing, and its own naming, properties and layers all follow the guidelines. Header - With Logo has since been renamed Brand App Bar in Figma, confirming it stays a distinct component rather than merging into Title Bar. What remains is bookkeeping on two other pages rather than work on this one: the site still lists Brand App Bar under its old name, and Detail Hero still needs a call on whether it belongs in the family at all. Both are tracked on their own component pages. (Family) C1 · Layer Structure & Naming
| Role | Element | Token | Value |
|---|---|---|---|
| All | Surface | — | #FFFFFF |
| All | Border | — | #E5EBF4 |
| All | Preamble | — | #005CE5 |
| All | Title | — | #0A2757 |
| All | Description | — | #6780A9 |
| All | Counter background | — | #EEF2F9 |
| All | Counter value | — | #072592 |
| All | Leading media placeholder | — | #D7E0EF |
| Icon | Trailing icon placeholder | — | #D7E0EF |
| Link | Link label | — | #005CE5 |
| Edit | Edit icon and label | — | #005CE5 |
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.*
TrailingMedia and hasLeadingMedia are the set’s two variant properties; hasPreamble, hasDescription and hasCounter are booleans that change what renders without adding variants. Image-Slot (leading) and Icon-Slot (trailing Icon) are Figma Slots; the Counter is a nested Counter instance. Boolean defaults and text exposure are not readable with the plugin.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| TrailingMedia — Icon, Link, Edit, None | .ebTrailingMedia(.icon / .link / .edit) | trailingMedia = EBTrailingMedia.Icon / Link / Edit / None |
| hasLeadingMedia — True, False | .ebLeadingMedia { … } when True | leadingMedia = { … } when True, else null |
| hasPreamble — True, False | .ebPreamble("…") when True | preamble = "…" or null |
| hasDescription — True, False | .ebDescription("…") when True | description = "…" or null |
| hasCounter — True, False | .ebCounter(0) when True | counter = 0 or null |
| Image-Slot (slot) | .ebLeadingMedia { Image("…") } | leadingMedia = { Icon(…) } |
| Icon-Slot (slot, inside Trailing Media › Icon) | .ebTrailingMedia(.icon(Image("…"))) | EBTrailingMedia.Icon { Icon(…) } |
| Title (text) | EBSectionHeader("Heading") | title = "…" |
| Preamble (text) | .ebPreamble(_:) | preamble = "…" |
| Description (text) | .ebDescription(_:) | description = "…" |
EBSectionHeader("Heading")
.ebPreamble("Preamble")
.ebDescription("Description goes here")
.ebCounter(0)
.ebLeadingMedia { Image("placeholder") }
.ebTrailingMedia(.icon) EBSectionHeader(
title = "Heading",
preamble = "Preamble",
description = "Description goes here",
counter = 0,
leadingMedia = { Icon(…) },
trailingMedia = EBTrailingMedia.Icon
) EBSectionHeader("Heading")
.ebPreamble("Preamble")
.ebDescription("Description goes here")
.ebCounter(0)
.ebLeadingMedia { Image("placeholder") }
.ebTrailingMedia(.link) EBSectionHeader(
title = "Heading",
preamble = "Preamble",
description = "Description goes here",
counter = 0,
leadingMedia = { Icon(…) },
trailingMedia = EBTrailingMedia.Link
) EBSectionHeader("Heading")
.ebPreamble("Preamble")
.ebDescription("Description goes here")
.ebCounter(0)
.ebLeadingMedia { Image("placeholder") }
.ebTrailingMedia(.edit) EBSectionHeader(
title = "Heading",
preamble = "Preamble",
description = "Description goes here",
counter = 0,
leadingMedia = { Icon(…) },
trailingMedia = EBTrailingMedia.Edit
) EBSectionHeader("Heading")
.ebPreamble("Preamble")
.ebDescription("Description goes here")
.ebCounter(0)
.ebLeadingMedia { Image("placeholder") } EBSectionHeader(
title = "Heading",
preamble = "Preamble",
description = "Description goes here",
counter = 0,
leadingMedia = { Icon(…) },
trailingMedia = EBTrailingMedia.None
) | Requirement | iOS | Android |
|---|---|---|
| Heading | Title carries .accessibilityAddTraits(.isHeader); Preamble and Description are read as part of it. | Modifier.semantics { heading() } on the title; mergeDescendants on the content block. |
| Counter value | .accessibilityValue("3 items") on the heading — the bare number is ambiguous. | stateDescription = "3 items" on the heading. |
| Link and Edit actions | Each is its own Button with the visible text as label; .isLink trait on Link. | Separate TextButton / IconButton with contentDescription; never merged into the heading. |
| Leading media | .accessibilityHidden(true) when decorative; a label when it identifies the section. | contentDescription = null when decorative. |
| Minimum target | Link (61 × 22) and Edit (112 × 24) need a 44 pt hit area. | Link and Edit need a 48 dp touch target. |
Do
Use Link when the section continues on another screen — "View All".
Don't
Don’t use Link for an in-place action; that is Edit.
Do
Turn hasCounter on only when the count changes what the user does next.
Don't
Don’t show a static total in the counter.
Do
Keep the Title to one line inside the content width — 312 less leading and trailing media.
Don't
Don’t wrap the title; move detail into Description.
Do
Use hasLeadingMedia for a section icon or avatar at 46 × 46.
Don't
Don’t put an illustration in Image-Slot; the frame is fixed at 46.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | LeadingMedia › Image-Slot, HeaderContent › Preamble / DescriptionRow › CounterSlot / Description, Trailing Media — read on 4363:11466. |
| C2 | Variant & Property Naming | Ready | TrailingMedia and hasLeadingMedia with Title Case values; the three has… booleans are real True / False. |
| C3 | Token Coverage | Ready | Preamble → Primary/Label/Small, Title → Primary/Headlines/Section, Description → Secondary/Bold/Caption. Colour variable bindings are not readable with the plugin — confirm in Dev Mode. |
| C4 | Native Mappability | Ready | One enum, four booleans, two slots, three strings — maps 1:1 onto EBSectionHeader. |
| C5 | Interaction State Coverage | Not Applicable | Interaction states ruled out of scope (v2.x): the header is static; Link and Edit take their states from the Text Button. |
| C6 | Asset & Icon Quality | Needs Refinement | Leading and trailing icons are Slots with instance placeholders. The Edit icon carries a shape_full BOOLEAN_OPERATION — flatten it in the icon library. |
4 TrailingMedia × 2 hasLeadingMedia = 8 variants; hasPreamble, hasDescription and hasCounter are booleans and do not multiply the count
| TrailingMedia | hasLeadingMedia | Node | Dimensions |
|---|---|---|---|
| Icon | True | 4363:11466 | 360 × 100 |
| Icon | False | 4363:11465 | 360 × 100 |
| Link | True | 4363:11463 | 360 × 100 |
| Link | False | 4363:11461 | 360 × 100 |
| Edit | True | 4363:11462 | 360 × 100 |
| Edit | False | 4363:11459 | 360 × 100 |
| None | True | 4368:11366 | 360 × 100 |
| None | False | 4363:11464 | 360 × 100 |
TrailingMedia — Icon, Link, Edit, None — with the four booleans as panel toggles; geometry, colours and the three text styles verified on 4363:11466 and its siblings against the exports, and the preview now top-anchors at 24 like the component. Padding, gap, alignment and colour tokens are not readable with the plugin and stay —.TrailingMedia × booleans schema. Property Mapping one row per property with the two slots, Usage Snippets per TrailingMedia, Guidelines added, Scorecard regraded, Variants Inventory on the eight live nodes.Edit icon inside Trailing Media on 4363:11462 contains shape_full; flatten it in the icon library. Filed from the scorecard for the Component Review.Counter confirmed correct; Interaction states ruled out of scope; Header-family restructure closed.preamble, leadingMedia, trailing). Open