East Blue
KeepReady
Countdown - Unit Component link

One slice of a countdown — a number and the unit it counts. Stacked for the boxed and bar layouts, inline for the pill.

Keep — the piece every countdown is built from
All four DS Health traits pass. Countdown assembles four of these in all three of its layouts, so the number and its label are drawn one way everywhere. Layout = Stacked | Inline covers both arrangements the system needs: the number above its label in the boxed and bar styles, and the two side by side in the pill. Colour comes from whatever places it — see the note on that in Countdown.
In Context

Never used on its own. Four instances sit inside every Countdown, one per unit, and the layout that holds them decides whether they stack or run inline.

Live Preview
Properties
Layout
Value
UnitLabel
hasUnitLabel
DS Health
Reusable
Pass
Every unit in every countdown layout is this component — four per Countdown, across all eighteen of its versions.
Self-contained
Pass
Carries its own two text layers and both arrangements. It holds no box, border or padding, which is what lets the same piece sit in a filled box, a bar and a pill.
Consistent
Pass
Both versions read #time then #unit. Stacked centres the label under the number; Inline sets both at the same size on one line.
Composable
Pass
Instanced by Countdown in all three styles, and reaches Countdown Promo through the Countdown it contains.
Behavior
State iOS Android Figma Property Notes
Layout=Stacked N/A N/A 25 × 34 Number above label. Used by the Per and One styles.
Layout=Inline N/A N/A hugs content Number and label on one line at 16px. Used by the Pill style.
#time N/A N/A String Always two digits — a leading zero keeps the row from shifting as the value falls.
#unit N/A N/A String "days" / "hrs" / "mins" / "secs" stacked; "d" / "h" / "m" / "s" inline.
Issues
  • The label property is one word. It was Unit Label, with a space. Property names become parameters, and a space has to be transformed away wherever that happens — the same defect as week 6 on Date Picker - Calendar. It is now UnitLabel, which also pairs with the hasUnitLabel boolean beside it. C2 · Variant & Property Naming
  • The component says what it is. It was called Base Time-Unit Primitive — a description of its place in the architecture rather than of the object. Everything else in the system is named for the thing itself, so it is now Countdown - Unit, matching the family prefix. C1 · Layer Structure & Naming
  • The setting has real values. It shipped with Figma's untouched default, Property 1=Default — a dropdown with one meaningless value. It is now Layout = Stacked | Inline, where both values do something. C2 · Variant & Property Naming
  • The label layer is called what it holds. #blurb became #unit. In the naming guidelines a blurb is a short descriptive passage; this layer holds "days". C2 · Variant & Property Naming
  • The pill stopped abusing the stacked version. Pill used to take the stacked unit, put the whole string into #time as "00d", override the type from Bold 20 to SemiBold 16, and leave #unit reading "days" on all four instances just outside the pill's edge. The Inline version replaced all of that — 24 dead layers across the six pill versions are gone. C1 · Layer Structure & Naming
Recommendations
  • Raise the muted label colour on filled surfaces if the palette allows. On the bold blue treatment the label renders at roughly 3.2:1 against its box, where 10px text wants 4.5:1. It was raised one tier already. The ceiling is the surface rather than the token — pure white on that blue reaches only about 4.4:1 — so clearing it needs a darker box, which the brand palette does not currently offer. Kept as-is deliberately to preserve the hierarchy between the number and its label. Token
  • Let the number and label be separate parameters natively. v1.1: Applied — Property Mapping takes them as two values, value: Int and unit: EBTimeUnit, never a preformatted string. The enum goes further than the recommendation asked: the platform renders the label from it, so the label follows the device locale instead of shipping whatever a designer typed in Figma. Docs
Layouts
Stacked
Properties
Value
UnitLabel
hasUnitLabel
Properties
Layout Stacked
Value 00
UnitLabel days
hasUnitLabel true
Versions 2
Colors
#time #005CE5
#unit #005CE5
Typography
#time Primary/Headlines/Segment
#unit Primary/Label/Light/Tiny
Layout
Height 34px
Width 25px
Padding H 0px
Padding V 0px
Gap 0px — the label sits flush under the number
Alignment Center (derived)
Colors

Two text layers, one colour, no states — the unit is never pressed or disabled on its own. It also paints no surface: whatever sits behind it belongs to the countdown that places it.

Role Token Value
#time text/color-text-primary #005CE5
#unit text/color-text-primary #005CE5
Inline
Properties
Value
UnitLabel
hasUnitLabel
Properties
Layout Inline
Value 00
UnitLabel days
hasUnitLabel true
Versions 2
Colors
#time #005CE5
#unit #005CE5
Typography
#time Primary/Label/Light/Base
#unit Primary/Label/Light/Base
Layout
Height 16px
Width 55px
Padding H 0px
Padding V 0px
Gap 0px — the label follows the number with no space
Alignment Baseline (derived)
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:countdown:1.0.0")

Import

import EastBlueDS
import com.eastblue.ds.countdown.*

Planned API — the native library does not exist yet. The artifact is the Countdown family, not this component: Unit, Promo and Countdown itself all ship in <code>com.eastblue.ds:countdown</code> and import <code>com.eastblue.ds.countdown.*</code>. In practice a team places a Countdown rather than a Unit; this is the piece it renders.

Property Mapping

Four properties, in the order the Figma property panel lists them. One shape difference is deliberate and worth knowing: Figma exposes UnitLabel as free text because a designer has to type something to see it, but the native parameter is an enum the platform localises. The string in Figma is what that enum renders in English — passing a string through would put days in front of every user regardless of locale, which is what the Accessibility and Usage Guidelines sections both argue against.

Figma PropertySwiftUICompose
Layout — Stacked, Inline layout: EBCountdownUnitLayout = .stacked layout: EBCountdownUnitLayout = Stacked
Value (text) value: Int — zero-padded on render, so Figma's "00" is what a value of 0 draws value: Int — same
UnitLabel (text) unit: EBTimeUnit — the platform renders the label. Figma's text is the result, not an input: a typed "days" would hardcode English into every instance unit: EBTimeUnit — same, resolved against the device locale
hasUnitLabel — true, false showsUnit: Bool = true showsUnit: Boolean = true
Usage Snippets Planned API
Stacked — the boxed and bar styles
EBCountdownUnit(
    value: 0,
    unit: .days,
    layout: .stacked
)
EBCountdownUnit(
    value = 0,
    unit = EBTimeUnit.Days,
    layout = EBCountdownUnitLayout.Stacked
)
Inline — the pill
EBCountdownUnit(
    value: 0,
    unit: .days,
    layout: .inline
)
EBCountdownUnit(
    value = 0,
    unit = EBTimeUnit.Days,
    layout = EBCountdownUnitLayout.Inline
)
Accessibility
RequirementiOSAndroid
The unit is not announced on its own .accessibilityHidden(true) — the countdown announces the whole duration Modifier.clearAndSetSemantics {} on the unit
Labels come from the locale DateComponentsFormatter supplies the unit wording MeasureFormat with the user's locale
Numerals respect the user's numbering system NumberFormatter rather than string interpolation NumberFormat.getInstance(locale)
Usage Guidelines

Do

Pass the number and the unit separately so the platform can localise the label.

Don't

Don't pass a preformatted "00d" string — it can't be translated or re-laid-out.

Do

Keep two digits, including the leading zero.

Don't

Don't let the width change as the value drops; the row will jitter every second.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready Two text layers, #time and #unit, in both versions. No leftover or hidden layers.
C2 Variant & Property Naming Ready Layout = Stacked | Inline. The untouched Property 1 default is gone.
C3 Token Coverage Ready Both text layers are bound to text/color-text-primary, confirmed by design. The unit paints no surface of its own, so the contrast of a muted label on a filled box is the placing component's concern, not this one's.
C4 Native Mappability Ready Two labels in a stack or a row — trivially mappable, and the split keeps localisation possible.
C5 Interaction State Coverage Not Applicable Display only — a countdown is read, not operated.
C6 Asset & Icon Quality Ready No assets — type only.
Variants Inventory (2 total)

1 Layout setting × 2 values. Value, UnitLabel and hasUnitLabel are content settings and do not multiply the set.

LayoutSizeTypeUsed byNode
Stacked25 × 34Primary/Headlines/Segment over Primary/Label/Light/TinyPer · One5625:35647
Inline55 × 16Primary/Label/Light/Base throughoutPill7831:111597
1.1.0 — September 2026Minor
UnitLabel renamed, Style and Code tabs rebuilt — node 7831:111593
The label property is one word. Unit Label became UnitLabel. Property names become parameters, and a space has to be transformed away wherever that happens — the same defect as week 6 on Date Picker - Calendar. It now pairs with the hasUnitLabel boolean beside it. This is what makes the release a minor rather than a patch.
C2 resolved
Three of the four properties were undocumented. The page described Layout and nothing else; the Figma panel also carries Value, UnitLabel and hasUnitLabel. get_node_info cannot read property definitions, so the gap only surfaced when the property panel was checked directly — worth remembering as a limit of reading the node tree alone.
C2 resolved
The preview invented an abbreviation. It swapped days for d whenever Layout was Inline, and the Properties row documented that swap as a fact with a variants override. Figma has days in both versions — the characters are the same on both nodes. The swap was a preview convenience written up as a specification.
C1 resolved
Two colour rows described a component that is not this one. They recorded white text and a muted label on a filled box, neither of which the unit paints — it has no surface at all. Colours are now the two text layers, both text/color-text-primary, confirmed by design.
C3 resolved
Typography was three font specs. Proxima Soft Bold · 20 / 24 · 0 and its siblings gave way to the styles the layers resolve to: Primary/Headlines/Segment over Primary/Label/Light/Tiny when Stacked, and Primary/Label/Light/Base for both layers when Inline.
C3 resolved
One card became two. Layout is the driving property, so Stacked and Inline each get a card, with the three content settings as controls on both.
Docs
Layout had none of the seven keys — Dimensions, Arrangement and an Alignment whose value read "label centred under the number". Now Height · Width · Padding H · Padding V · Gap · Alignment on each card. Radius is omitted: the unit paints no shape to round.
Docs
The Inline preview rendered at the Stacked sizes. The stylesheet hardcoded 20px and 10px with no Inline override, so the pill layout drew a 20px number over a 10px label where Figma has both at 16 / 16. The preview also declared font-family: inherit, so every layer drew in the documentation font — all of them are Primary/*, which is Proxima Soft.
Docs
The install block pointed at coordinates that will never exist. gcash/east-blue-ios and com.gcash.eastblue:components:1.0.0, with no Import line. It now cites the Countdown family artifact com.eastblue.ds:countdown:1.0.0 and imports com.eastblue.ds.countdown.*.
Docs
Property Mapping named layers and missed a property. Two of its three rows were #time and #unit rather than Value and UnitLabel, and hasUnitLabel was absent. Four rows now, with the type corrected from UnitLayout to EBCountdownUnitLayout.
C4 resolved
Figma and the native API disagree about the unit, deliberately. Figma exposes UnitLabel as free text because a designer has to type something to see it; the parameter is unit: EBTimeUnit, an enum the platform localises. Figma's string is what that enum renders in English. The mapping now says so outright rather than presenting a string parameter that would ship "days" to every user — which is what the Accessibility and Usage Guidelines sections already argued against.
C4 resolved
C3 was held open for a contrast problem on another component's surface. The note read "the muted label on filled surfaces sits below 4.5:1"; the unit never paints that surface. Both its text layers are bound and confirmed, so C3 moves to Ready. The recommendation about raising that colour stays open here but belongs to whatever places the unit — it should move to Countdown when that component is reviewed.
C3 resolved
Variants understated one size and carried no node IDs. Inline read "hugs · 16 tall"; the node reports 55 × 16. Both rows now cite their node and name the resolved type styles rather than font specs. Code Connect is emptied, and a getSnippet keeps the DEV block following all four properties — including dropping unit for showsUnit: false when the label is switched off.
Docs
1.0.0 — August 2026Initial
Extracted as a primitive · node 7831:111593
Split out of Countdown. The old component drew its own numbers in every layout; the unit is now one shared piece.
Family
C1 — renamed from Base Time-Unit Primitive to Countdown - Unit, matching the family prefix.
C1 resolved
C2 — Property 1=Default replaced with Layout = Stacked | Inline.
C2 resolved
C2 — #blurb renamed to #unit, which is what it holds.
C2 resolved
C1 — the Inline version replaced Pill's overrides. Pill previously packed "00d" into #time, changed the type style, and left #unit reading "days" outside the pill on all four instances.
C1 resolved
C3 — muted label raised one tier on filled surfaces, from roughly 2.9:1 to 3.2:1. Still under 4.5:1; the surface, not the token, is the ceiling.
C3 partial