The month and year chips in the calendar header. Tapping one switches the calendar to its month or year view. Six versions — three states, with or without a caret.
State setting, matching the field trigger and the naming guidelines. A hasCaret option adds the disclosure indicator that was missing — without it the chips read as static labels rather than controls that open a view. It is badged Needs Refinement for one reason: at 24px tall the chip is well under the minimum touch target.Two instances sit between the chevrons in the calendar header — one for the month, one for the year. Tapping either switches Date Picker - Calendar into its Month or Year mode, where the chip is replaced by a static title and a back chevron.
hasCaret lets it be used where a disclosure indicator would be wrong.State like Date Picker does, and wraps in a Container like every other component in the family.Container, between the two chevrons.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| State=Default | N/A | N/A | #F6F9FD | Resting chip. Both header instances use this. |
| State=Pressed | N/A | N/A | #EEF2F9 | Momentary. Not used to mark which view is open. |
| State=Disabled | N/A | N/A | #FFFFFF | Surface stays, text and caret mute together. |
| hasCaret=true | N/A | N/A | Chevron Down | 16px icon instance. Widens the chip from 57 to 81. |
- The 24px chip is deliberate. The calendar header is a fixed strip, and a taller chip would push the grid down. The drawn chip stays 24px while the tap target is expanded natively to 44 pt on iOS and 48 dp on Android, which the Accessibility table sets out for both platforms. Confirmed with design — the same reasoning that settled the 32 × 32 cell. Growing the drawn chip is logged as a recommendation for a future redesign. C5 · Interaction State Coverage
- Two booleans became one State setting.
isDisabledandisPressedsat side by side, which allowed a pressed-and-disabled combination that means nothing. They are nowState = Default | Pressed | Disabled— the shape the naming guidelines ask for, and the one Date Picker already used. C2 · Variant & Property Naming - The setting with one value is gone. A
Kindsetting existed withMonthas its only value — a dropdown with nothing to choose, and no matchingYear. It was dropped: the same chip serves both positions, and only its text differs. C2 · Variant & Property Naming - The chip now says it opens something. It was a filled rectangle with a bold label and no disclosure indicator, which reads as a static chip.
hasCaretadds aChevron Downicon instance after the text — the same signal the field trigger's dropdown carries. The caret mutes along with the label in Disabled. C5 · Interaction State Coverage - The wrapper matches the family. The inner frame was
Label Container, spaced Title Case. It is nowContainer, like the cell and the weekday header. C1 · Layer Structure & Naming - The header no longer uses Pressed to mean selected. In the calendar's Day mode the month chip shipped in its Pressed version while the year chip sat at Default, which read as "this one is active". Both are Default now — pressed is a momentary state, not a way to mark the open view. C5 · Interaction State Coverage
- Give the chip a taller tap area. The drawn chip is 24px against 44 on iOS and 48 on Android — shorter even than the 32px day cell. The target is expanded natively today, which is the accepted trade for now, but an expanded target the user cannot see still misleads: two chips sit 8px apart while both claim 44. Worth growing the drawn chip whenever the calendar header is next reworked. Not a blocker for this release. A11y
- Announce the chip as a button that opens a picker. v1.1: Applied — the Accessibility table now carries a Role / trait row (
.accessibilityAddTraits(.isButton)·Modifier.semantics { role = Role.Button }) alongside a label row that names the value and the action together, "August, select month" rather than "August". Both platforms answered. A11y - Rename the component to
Date Picker - Header Triggerin Figma. v1.1: Applied — node6779:105937now readsDate Picker - Header Trigger, so the chip groups with Cell, Header, Calendar and the picker itself in the assets panel. The recommendation described it as still namedHeader Trigger; that has not been true since the rename. Rename
Three states, six versions. The caret is a stroke, not a fill, which is why it carries border tokens rather than icon ones. Disabled swaps the surface to white and mutes the label and caret to the same value from two different tokens.
| Role | Token | Default | Pressed | Disabled |
|---|---|---|---|---|
| Container surface | bg/color-bg · pressed bg/color-bg-strong · disabled bg/color-bg-primary-inverse | #F6F9FD | #EEF2F9 | #FFFFFF |
| #text | text/color-text · disabled text/color-text-disabled | #0A2757 | #0A2757 | #C2CFE5 |
| Chevron Down | border/color-border-strongest · disabled border/color-border-disabled | #445C85 | #445C85 | #C2CFE5 |
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:date-picker:1.0.0")
Import
import EastBlueDS import com.eastblue.ds.datepicker.*
Planned API — the native library does not exist yet. The artifact is the Date Picker family, not this component: Cell, Header, Header Trigger, Calendar and the picker itself all ship in <code>com.eastblue.ds:date-picker</code> and import <code>com.eastblue.ds.datepicker.*</code>.
Figma properties mapped to the intended native parameters, in the order the Figma property panel lists them. State is the one property that is not a single parameter: Default and Disabled are a flag, while Pressed is what the platform reports while a finger is down.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| State — Default, Pressed, Disabled | isDisabled: Bool = false — Pressed is the momentary press state, not a parameter | enabled: Boolean = true — Pressed comes from the InteractionSource |
| hasCaret — true, false | hasCaret: Bool = true | hasCaret: Boolean = true |
| Label (text) | label: String | label: String |
EBDatePickerHeaderTrigger( label: "Label", hasCaret: true )
EBDatePickerHeaderTrigger( label = "Label", hasCaret = true )
| Requirement | iOS | Android |
|---|---|---|
| Label | Button with .accessibilityLabel("August, select month") | Modifier.clickable(onClickLabel = "Select month") |
| Role / trait | .accessibilityAddTraits(.isButton) | Modifier.semantics { role = Role.Button } |
| Minimum target | .frame(minHeight: 44) around the 24pt chip | Modifier.minimumInteractiveComponentSize() — 48dp |
| Dynamic type | Supported, scales to AX5 — the chip hugs, so width grows with the label | sp units, scales with the system font scale |
| Caret is decorative | .accessibilityHidden(true) on the chevron | contentDescription = null |
Do
Turn the caret on wherever the chip opens a view.
Don't
Don't ship a bare chip that looks identical to a static label.
Do
Keep both chips in Default while the calendar is on the day view.
Don't
Don't use Pressed to mark which view is open — that's a selection meaning on a momentary state.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | Container → #text plus an optional icon instance. |
| C2 | Variant & Property Naming | Ready | State replaced two booleans; hasCaret follows the boolean prefix convention with lowercase values. |
| C3 | Token Coverage | Ready | Three surfaces and two text colours, all standard tokens. |
| C4 | Native Mappability | Ready | A labelled button with an optional trailing icon. |
| C5 | Interaction State Coverage | Ready | All three states are built across both caret options, and there is no Focused state by design — these are mobile components. The 24px chip is a deliberate visual size; the tap target is expanded natively to 44 pt / 48 dp, as the Accessibility table sets out. |
| C6 | Asset & Icon Quality | Ready | The caret is a Chevron Down icon instance that recolours per state. |
3 State × 2 hasCaret = 6 variants — the matrix is complete, every combination is built.
| State | hasCaret | Surface | Width | Node |
|---|---|---|---|---|
| Default | false | #F6F9FD | 57 | 6493:75116 |
| Pressed | false | #EEF2F9 | 57 | 6493:73968 |
| Disabled | false | #FFFFFF | 57 | 6493:73974 |
| Default | true | #F6F9FD | 81 | 7409:160301 |
| Pressed | true | #EEF2F9 | 81 | 7409:160304 |
| Disabled | true | #FFFFFF | 81 | 7409:160307 |
Header Trigger and recommended the Date Picker - prefix. Node 6779:105937 now reads Date Picker - Header Trigger, so the chip groups with Cell, Header, Calendar and the picker in the assets panel. This is what makes the release a minor rather than a patch.Primary/Bold/Subheading, which is not a style in the database. The layer resolves to Primary/Label/Base. The Font row spelling out Proxima Soft Bold · 16 / 16 · +0.25 is gone — that lives in the text style.border/color-border-strongest and border/color-border-disabled rather than an icon token. A Colors by State table now covers all three roles across all three states.bg/color-bg-subtle, bg/color-bg-subtle-pressed and bg/color-bg-main; the bindings are bg/color-bg, bg/color-bg-strong and bg/color-bg-primary-inverse. The hex values were right throughout — only the token paths were wrong, which is the worse half to get wrong..eb-preview-dphdr declared no font, so it inherited the documentation font — BarkAda — through .eb-preview-scope and body, while the component is Proxima Soft Bold. Proxima Soft was loaded the whole time; the preview simply never asked for it.currentColor, so Default and Pressed rendered #0A2757 instead of #445C85. Disabled looked correct only by coincidence — the text and border disabled tokens both land on #C2CFE5.M4.5 6.5L8 10L11.5 6.5 at 2, replacing an approximation at 1.6.Corner radius, Gap to caret, Caret and Touch target while missing Padding V and Alignment. Now Height · Width · Radius · Padding H · Padding V · Gap · Alignment, each read off the auto-layout panel, with Width switching to Hug (57px) when the caret is off.gcash/east-blue-ios and com.gcash.eastblue:components:1.0.0, with no Import line at all. Under the family rule the artifact is com.eastblue.ds:date-picker — the whole Date Picker family, not this component — imported as com.eastblue.ds.datepicker.*.HStack(spacing: 4) and Row(horizontalArrangement = …) assembling two triggers — how to draw a header, not how to use this component. One snippet per driving value now, built from the same definition as the spec card and the live preview.EBPickerHeaderTrigger, and the mapping offered showsCaret for a property Figma calls hasCaret. All surfaces now read EBDatePickerHeaderTrigger with hasCaret and label, each tracing 1:1 to a property in the panel.#text; the Figma property is Label. Rows are now prose grouped by property with their values listed, and the Variants Inventory gained the node ID for each of the six versions.isDisabled and isPressed collapsed into State. Interaction states belong on one setting, not on parallel booleans that permit combinations with no meaning.Kind setting removed. It offered only Month, with no Year counterpart.hasCaret added. A Chevron Down instance now signals that the chip opens a view; it mutes with the label in Disabled.Label Container renamed to Container, matching the rest of the family.