East Blue
KeepReady
Date Picker - Cell Component link

The one selectable cell used everywhere in the picker — day numbers in the calendar grid, and month and year labels in the header views. 16 versions.

Keep — two components merged into one, cleanly
All four DS Health traits pass. Date Picker - Item and Month and Year Picker - Item are gone; both are now Kind values on this one component. The old Type setting that mixed display role with selection state is split into Role and Selection, every version wraps in a Container, and the Today ring is identical across both kinds. It is badged Needs Refinement for one reason: the cell is 32×32, below the 44×44 and 48×48 minimum touch targets.
In Context

Day cells fill the seven-column calendar grid; month and year cells fill the three-column header views. The same component serves both, which is what keeps selection, today and disabled looking identical wherever they appear.

Live Preview
1
Properties
Kind
Role
Selection
isDisabled
Day
DS Health
Reusable
Pass
One cell covers the day grid and both header views. Where the system used to keep two near-identical components, a single Kind value now tells them apart.
Self-contained
Pass
Carries its own surface, radius, type style and every state it can be in. The range strip is drawn inside the cell rather than by the row that holds it.
Consistent
Pass
Both kinds wrap in a Container holding one #text. Selection is #005CE5 with white text in both; Today is a #005CE5 ring in both; Selected text is SemiBold 600 in both.
Composable
Pass
Instanced by Date Picker - Calendar in all three modes — seven per row in Day, twelve in Month, eighteen in Year.
Behavior
State iOS Android Figma Property Notes
Kind=Day N/A N/A 32 × 32 Circular container, radius 24.
Kind=MonthYear N/A N/A 59 × 32 Rounded rectangle, radius 8. Header views only.
Role=Today N/A N/A ring #005CE5 stroke and text, no fill.
Role=Prev-Next N/A N/A muted Adjacent-month days. Tappable, not disabled.
Selection=Selected N/A N/A filled #005CE5 fill, white text. Also carries the pressed meaning.
Selection=Range-* N/A N/A strip #E5F1FF strip bleeding 10px past the cell to meet its neighbour. Day only.
isDisabled=true N/A N/A muted Not available on the range or Prev-Next versions.
Issues
  • The 32 × 32 cell is deliberate. A seven-column grid at 312px leaves 32px per cell, so the drawn circle stays 32 × 32 by design. The tap target is not the circle: it expands natively to 44 pt on iOS and 48 dp on Android, which the Accessibility table sets out for both platforms. Confirmed with design — the intended trade for now, not a gap. Sizing the cell to its target is logged as a recommendation for a future redesign. C5 · Interaction State Coverage
  • Two cell components became one. Date Picker - Item and Month and Year Picker - Item are gone. Both are now Kind values on this component, which is what stopped the two from drifting apart on state coverage, ring thickness and selection colour. C2 · Variant & Property Naming
  • Display role and selection are separate settings. The old Type setting mixed the two, so "this is today" and "this is selected" competed for one slot. They are now Role and Selection, which is what made the Today and Selected combination expressible at all. C2 · Variant & Property Naming
  • Value names lost their punctuation and spacing. Range (Middle) is now Range-Middle, alongside Range-Start and Range-End. Kind reads MonthYear rather than carrying a slash, and the booleans are lowercase true and false. C2 · Variant & Property Naming
  • Every version wraps the same way. Day cells used to wrap in container and month cells in Label Container, and the month cell's inner frame was called Month even on the year view. All sixteen now read Container → #text. C1 · Layer Structure & Naming
  • The range strip is drawn once, consistently. Range-Start carried two overlapping rectangles whose names sat on the wrong sides, Range-Middle painted #E5F1FF twice, and the plain Selected cell shipped two hidden range rectangles it never used. Each range version now has one rectangle, correctly named, bleeding the same 10px. C1 · Layer Structure & Naming
  • Selected reads the same weight on both kinds. Month and year labels were Bold 700 while day numbers were SemiBold 600 in the same Selection=Selected state. Both are SemiBold 600 now. C1 · Layer Structure & Naming
  • Today and Selected no longer pretend to differ. Four Role=Today, Selection=Selected versions existed but rendered identically to Role=Default, Selection=Selected — the day cell's only difference was a stroke in the same colour as its own fill. They were dropped rather than given a treatment: once a date is selected, the selected fill is the signal. C5 · Interaction State Coverage
  • Adjacent-month days got a stronger colour. Prev-Next moved from the weakest text token to the next step up, taking contrast against white from roughly 2.4:1 to about 4.0:1. These are real tappable days, not disabled ones, so they need to be readable. C3 · Token Coverage
Recommendations
  • Size the cell to the touch target in a future redesign. The 32 × 32 cell is deliberate today — the seven-column grid leaves 32px, and the tap target is expanded natively to 44 pt / 48 dp. But an expanded target the user cannot see still misleads: two adjacent days sit 32px apart while both claim 44. Worth revisiting whenever the calendar’s grid is next opened up, so the drawn cell and the tappable one are the same thing. Not a blocker for this release. A11y
  • Rename the component to Date Picker - Cell in Figma. The component is still called Picker Cell at node 5943:41825. The family agreed on the Date Picker - prefix so the five components group together in the assets panel. Rename
  • Document that Selected carries the pressed meaning. There is no separate pressed version, by design — tapping a cell selects it. Worth noting in the Code tab that Compose attaches a ripple to clickable surfaces by default, so Android will show press feedback the design does not draw. Docs
  • Give the row the range strip, not the cell. v2.1: Closed — decided against. The strip stays on the cell and bleeds past its edge on purpose: it meets the neighbouring cell so the highlight reads as one continuous bar across the row. Moving it to the row would mean the row deciding which days are in range, which is the cell's job. Composition
  • Take Prev-Next one more step up the token scale. v2.1: Applied — Prev-Next sits on text/color-text-weaker. That is the next step available that does not read as disabled, chosen over a higher-contrast value on purpose: going further would make an adjacent-month day look unavailable. Token
Kinds
Day
1
Properties
Role
Selection
isDisabled
Day
Properties
Kind Day
Role Default
Selection None
isDisabled false
Day 1
Colors
Container surface #FFFFFF
#text #0A2757
#text — Today #005CE5
Border — Today #005CE5
Container — Selected #005CE5
#text — Selected #FFFFFF
Range highlight #E5F1FF
#text — Prev-Next #6780A9
Typography
#text Primary/Label/Light/Small
Layout
Height 32px
Width 32px
Radius 24px
Padding H 6px (derived)
Padding V 9px (derived)
Alignment Center
Day — Colors

The cell has no pressed state, so that column is blank throughout. Range and Prev-Next exist only on Day and have no disabled version.

Role Token DefaultPressedDisabled
Container surface bg/color-bg-primary-inverse #FFFFFF – #FFFFFF
#text text/color-text · disabled text/color-text-disabled #0A2757 – #C2CFE5
#text — Today text/color-text-primary · disabled text/color-text-primary-disabled #005CE5 – #9BC5FD
Border — Today border/color-border-primary · disabled border/color-border-primary-disabled #005CE5 – #9BC5FD
Container — Selected bg/color-bg-primary · disabled bg/color-bg-primary-disabled #005CE5 – #9BC5FD
#text — Selected text/color-text-inverse #FFFFFF – #FFFFFF
Range highlight bg/color-bg-info-weakest #E5F1FF – –
#text — Prev-Next text/color-text-weaker #6780A9 – –
MonthYear
Label
Properties
Role
Selection
isDisabled
Text
Properties
Kind MonthYear
Role Default
Selection None
isDisabled false
Text Label
Colors
Container surface #FFFFFF
#text #0A2757
#text — Today #005CE5
Border — Today #005CE5
Container — Selected #005CE5
#text — Selected #FFFFFF
Typography
#text Primary/Label/Light/Small
Layout
Height 32px
Width 59px
Radius 8px
Padding H 12px (derived)
Padding V 9px (derived)
Alignment Center
MonthYear — Colors

Identical palette to Day — the two kinds differ in width and corner radius, never in colour. MonthYear has no Range or Prev-Next version.

Role Token DefaultPressedDisabled
Container surface bg/color-bg-primary-inverse #FFFFFF – #FFFFFF
#text text/color-text · disabled text/color-text-disabled #0A2757 – #C2CFE5
#text — Today text/color-text-primary · disabled text/color-text-primary-disabled #005CE5 – #9BC5FD
Border — Today border/color-border-primary · disabled border/color-border-primary-disabled #005CE5 – #9BC5FD
Container — Selected bg/color-bg-primary · disabled bg/color-bg-primary-disabled #005CE5 – #9BC5FD
#text — Selected text/color-text-inverse #FFFFFF – #FFFFFF
Installation Planned API

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>. In practice most teams never call this directly; it is the cell the calendar grid renders.

Property Mapping

Figma properties mapped to the intended native parameters, in the order the Figma property panel lists them. Each cell shows one value — the day number or the month/year label — so the two text properties are alternatives, never both at once.

Figma PropertySwiftUICompose
Kind — Day, MonthYear kind: EBDatePickerCellKind kind = EBDatePickerCellKind.Day / MonthYear
Role — Default, Today, Prev-Next role: EBDatePickerCellRole = .default role: EBDatePickerCellRole = Default
Selection — None, Selected, Range-Start, Range-Middle, Range-End selection: EBDatePickerCellSelection = .none selection: EBDatePickerCellSelection = None
isDisabled — true, false isDisabled: Bool = false isDisabled: Boolean = false
Day (text) — shown when Kind is Day day: Int day: Int
Text (text) — shown when Kind is MonthYear text: String text: String
Usage Snippets Planned API
Day — a single date in the grid
EBDatePickerCell(
    kind: .day,
    day: 1
)
EBDatePickerCell(
    kind = EBDatePickerCellKind.Day,
    day = 1
)
MonthYear — a month or year in the picker
EBDatePickerCell(
    kind: .monthYear,
    text: "Label"
)
EBDatePickerCell(
    kind = EBDatePickerCellKind.MonthYear,
    text = "Label"
)
Accessibility
RequirementiOSAndroid
Tap area meets the platform minimum .frame(minWidth: 44, minHeight: 44) around the 32pt circle Modifier.minimumInteractiveComponentSize()
The date is announced, not the number .accessibilityLabel(date.formatted(date: .complete, time: .omitted)) contentDescription built from the full date
Selection is a state, not part of the label .accessibilityAddTraits(.isSelected) Modifier.semantics { selected = true }
Today is announced Append "Today" to the label when Role=Today Same, via stateDescription
Usage Guidelines

Do

Use Prev-Next for days belonging to the neighbouring month — they stay tappable.

Don't

Don't use Disabled for adjacent-month days; disabled means unavailable.

Do

Let Selected carry the pressed meaning — tapping a cell selects it.

Don't

Don't add a separate pressed style that competes with selection.

Do

Keep range selections on Day cells.

Don't

Don't try to range-select months or years; those views pick one value.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready All sixteen versions read Container → #text. Range rectangles are single, correctly named, and bleed a consistent 10px.
C2 Variant & Property Naming Ready Kind, Role, Selection and isDisabled follow the naming guidelines, with lowercase booleans and no punctuation in values.
C3 Token Coverage Ready Every colour is bound and confirmed by design. Prev-Next uses text/color-text-weaker — the next step available that does not read as disabled, chosen deliberately over a higher-contrast value.
C4 Native Mappability Ready Maps to a cell on both platforms. The range strip bleeds past the cell on purpose: it meets the neighbouring cell so the highlight reads as one continuous bar across the row.
C5 Interaction State Coverage Ready States are complete for the intended set — no Focused, since these are mobile components, and Selected carries the pressed meaning. The 32 × 32 cell 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 No icons or rasters — the cell is type on a shape.
Variants Inventory (16 total)

2 Kind × 3 Role × 5 Selection × 2 isDisabled permits 60 combinations; 16 are built. The matrix is sparse on purpose — MonthYear takes no range and no Prev-Next, range cells have no disabled version, and Prev-Next takes no selection.

KindVersionsCount
DayDefault · Today · Prev-Next, with the full Selection range10
MonthYearDefault · Today, None and Selected only6
View full Kind × Role × Selection breakdown (16 rows)
KindRoleSelectionisDisabledNode
DayDefaultNonefalse5943:41826
DayDefaultNonetrue5943:41829
DayTodayNonefalse5943:41832
DayTodayNonetrue5943:41835
DayDefaultSelectedfalse5943:41838
DayDefaultSelectedtrue5943:41843
DayDefaultRange-Startfalse6442:72593
DayDefaultRange-Middlefalse5943:41848
DayDefaultRange-Endfalse6442:72603
DayPrev-NextNonefalse5943:41853
MonthYearDefaultNonefalse6442:73668
MonthYearDefaultNonetrue6442:73665
MonthYearTodayNonefalse6442:73671
MonthYearTodayNonetrue6442:73674
MonthYearDefaultSelectedfalse6442:73662
MonthYearDefaultSelectedtrue6442:73677
2.1.1 — September 2026Patch
Family artifact and preview font — node 5943:41825
The Gradle artifact named this component, not its family. It read com.eastblue.ds:date-picker-cell, which was correct when v2.1.0 shipped and stopped being correct the same week: §3.2 now rules that an artifact is a family, never a component. Cell, Header, Header Trigger, Calendar and the picker itself all install com.eastblue.ds:date-picker. The Kotlin import was already on the family package and did not move.
Docs
The preview rendered in the wrong typeface. .eb-preview-dpcell declared font-family: inherit, which reads as a deliberate choice in a diff but resolves through .eb-preview-scope to body — the documentation font, BarkAda. The cell is Proxima Soft. The font was loaded the whole time; the preview simply never asked for it. Found on Header Trigger and swept back here.
Docs
The text properties did not move the preview. Typing into Day or Text updated the DEV snippet but not the cell, on both tabs: the renderer hardcoded kind === 'day' ? '1' : 'Label' and never read the value the control had already stored. It now takes the text and falls back to Figma’s defaults only when the field is empty.
Docs
The Overview had no way to set the text at all. Its panel offered Kind, Role, Selection and isDisabled and stopped there. Day and Text rows now sit after isDisabled in Figma’s panel order, and only the one belonging to the current Kind is shown — each cell carries one value, so the two are alternatives, never both.
Docs
The control keys still used the pre-rename names. Day’s control was keyed index and MonthYear’s label — the property names Figma used before v2.1.0 renamed them to Day and Text. Nothing user-facing was wrong, but the data file and the demo script disagreed with the Code tab. All nine references now read day and text.
Docs
2.1.0 — September 2026Minor
Text settings added, Style and Code tabs rebuilt — node 5943:41825
The day and the label can be set on a copy. The cell had one text layer and no way to fill it from an instance. It now carries two text settings — Day for the date number and Text for the month or year — named after what each shows rather than the generic Index and Label they started as. This is what makes the release a minor rather than a patch.
C2 resolved
One text setting was considered and rejected. A single Value property would serve both kinds, but Figma gives a text property one placeholder for every version — and "Value" overflows a 32 × 32 day cell. Two properties is the deliberate trade.
C2 resolved
The documented type style did not exist. Typography read Primary/SemiBold/Body, which is not a style in the database. The layer resolves to Primary/Label/Light/Small.
C3 resolved
Every colour is a named colour, confirmed by design. Two colours tables were written from nothing — the token paths had never been on the page. Prev-Next stays on text/color-text-weaker deliberately: the next step up would read as disabled.
C3 resolved
The invisible white fills are gone. Every version carried a white fill switched off on the component frame. Nothing drew it, but it read as a surface to anyone inspecting the layers.
C1 resolved
Default cells had no background in the preview. The preview painted a background only for Selected, so every Default cell rendered transparent while Figma's Container paints white on all sixteen versions.
Docs
The range strip painted over the selected circle. The preview had rebuilt the strip as a child of the cell, and a parent's background always sits behind its children — so no stacking order could fix it. The Container is now its own layer with the strip beneath, matching Figma, where the highlight is a sibling drawn before Container.
Docs
Disabled Today used the wrong blue. The preview drew its border and text in #C2CFE5, which is Default's disabled text. Today's disabled state is #9BC5FD on both.
Docs
Card titles carried raw Figma syntax. They read Kind=Day and Kind=MonthYear. Titles are the bare value.
Docs
The component had two names. The spec cards called it EBPickerCell while the Code tab and the live snippet called it EBDatePickerCell, and the argument names disagreed too — index against day. All three surfaces now build from one definition.
Docs
Install coordinates corrected. gcash/east-blue-ios and com.gcash.eastblue:components became AY-Org/eb-ds-ios and com.eastblue.ds:date-picker-cell:2.1.0, with the Kotlin import on the family package com.eastblue.ds.datepicker.
Docs
Usage Snippets were split by state, not by version. They showed "a selected day" and "a day inside a range"; they now show Day and MonthYear, the two values of the driving setting. Property Mapping gained the two text settings, and the Variants Inventory gained the full sixteen-row breakdown behind its summary.
Docs
The 32 × 32 cell is a decision, not a gap. The seven-column grid leaves 32px per cell, so the drawn circle stays 32 × 32; the tap target expands natively to 44 pt and 48 dp, which the Accessibility table sets out. Confirmed with design and moved out of Open Issues — C5 moves to Ready. Sizing the cell to its target is now a recommendation for a future redesign, not an open defect.
C5 resolved
Prev-Next’s token was already at the right step. The recommendation to raise it further is applied and closed: text/color-text-weaker is the last step before an adjacent-month day starts reading as unavailable. C3 moves to Ready.
C3 resolved
The range strip stays on the cell. The recommendation to move it to the row is closed, decided against — the strip bleeds past the cell on purpose so the highlight meets its neighbour and reads as one bar across the row. C4 moves to Ready.
C4 resolved
2.0.0 — August 2026Major
Consolidated rebuild — node 5943:41825
Two components became one. Date Picker - Item and Month and Year Picker - Item fold into this component as Kind=Day and Kind=MonthYear.
Family
C2 — Type split into Role and Selection. Display role and selection state no longer compete for one setting.
C2 resolved
C2 — value names cleaned. Range (Middle) → Range-Middle, Month/Year → MonthYear, booleans lowercased.
C2 resolved
C1 — one anatomy. container and Label Container both became Container.
C1 resolved
C1 — range strip rebuilt. One rectangle per range version, names matching their sides, 10px bleed throughout. Hidden range rectangles removed from the plain Selected cell.
C1 resolved
C5 — Today+Selected dropped. The four versions rendered identically to Default+Selected; selection now wins outright.
C5 resolved
C3 — Prev-Next token raised from the weakest step to the next, taking contrast from about 2.4:1 to about 4.0:1. Still short of 4.5:1.
C3 partial
C5 — touch target unchanged. The cell remains 32×32 against 44/48 minimums.
C5 open