KeepReady
Counter Component link

A small numeric badge used to display unread or pending counts on icons and rows.

Keep — all findings resolved
Rebuilt on node 4675:21497 in the 2026 Working File and cleared through v2.4. State and hasLimit follow the Property Naming Guidelines; all four variants are dimensionally consistent; every frame and text layer carries a correct semantic name (Count ×4, Separator ×2, Limit ×2, Plus ×2, LimitGroup ×2). Count and Limit are exposed as text properties and the Overflow affordance is property-bound. All four DS Health traits pass. The only item still open is Code Connect registration, blocked until the native library exists. Variant count stays at 4.
In Context

Counter appears inline with text to show counts — section headers for unread notifications, tab item badges for pending items, limit/slot usage displays.

Live Preview
5
Content
count
limit
maxDisplay
Properties
with limit
state
DS Health
Reusable
Pass
Generic count primitive — used across Section Header, Tab Item, and standalone notification contexts.
Self-contained
Pass
Owns its typography, color tokens, and radius. Nothing external required to render.
Consistent
Pass
State and hasLimit follow the Property Naming Guidelines, all four variants are dimensionally consistent, and every frame and text layer carries a correct, distinct semantic name — Count, Separator, Limit, Plus, LimitGroup.
Composable
Pass
Hugs content width, drops into any inline layout (Section Header, Tab Item) without manual sizing.
Behavior
State iOS Android Figma Property Notes
Default Yes Yes State=Default Brand-blue label (#072592) on the neutral chip. The normal presentation.
Disabled Yes Yes State=Disabled Muted label (#C2CFE5) on the same bg. Documented as a disabled context — a Counter sitting inside a disabled row or field. Zero-count styling is no longer modeled as a variant; derive it from count in code.
With limit Yes Yes hasLimit=True Renders "N / M" (e.g. "3 / 10") — for slot/limit displays like "beneficiaries used".
Without limit Yes Yes hasLimit=False Renders a single integer in a 24×24 circle. Used for unread counts, inbox badges.
Pressed / Focused N/A N/A Counter is display-only — no interactive states.
Overflow (99+) Yes Yes <code>Overflow</code> layer A hidden Overflow frame holding a + glyph sits in the two hasLimit=False circle variants only — it was removed from the slash format in v2.1. Single-integer clamps at maxDisplay (default 99) → "99+"; slash format clamps at limit. Clamping is handled in code.
Issues
  • Code Connect mappings not registered. Blocked until the native library exists. Everything upstream is ready: State maps to a two-value enum, hasLimit to a Bool, and Count / Limit to text parameters. Registration is mechanical once there is a component to link to. C7 · Code Connect Linkability
  • with limit renamed to hasLimit. v2.0: Rebuilt on node 4675:21497. The property is now hasLimit with True/False values — a real Figma boolean toggle that maps directly to Swift Bool / Kotlin Boolean. The State axis was also recased to PascalCase, bringing both properties in line with the Property Naming Guidelines. (C2) C2 · Variant & Property Naming
  • Applied — Rename recommendation shipped. v2.0: Applied — with limit: yes/nohasLimit: True/False, exactly as recommended. Logged here rather than in an Applied tab because overview.appliedRecommendations does not yet exist in the schema. (Rename) C2 · Variant & Property Naming
  • State=Disabled semantics confirmed. v2.0: Closed by owner decision — Disabled describes the control context (a Counter sitting inside a disabled row or field), not a zero count. Zero-count styling is derived from count in code and is deliberately not modeled as a variant. This also settles the contrast question: the muted label (#C2CFE5 on #EEF2F9, 1.4:1) is disabled text, which WCAG 1.4.3 exempts. (Docs) C2 · Variant & Property Naming
  • Overflow clamp rule settled. v2.0: Closed by owner decision — no further spec work required. Single-integer format clamps at maxDisplay (default 99) and renders "99+"; slash format clamps at limit when count > limit. Handled in code; the Figma Overflow layer only supplies the + glyph. (C5) C5 · Interaction State Coverage
  • Two use cases documented. v2.0: Closed — single-integer answers how many of X are there (notifications, unread, pending); slash format shows progress against capacity (slots used, steps completed). Captured in the Behavior table and the Style tab; no further action. (Docs) C4 · Native Mappability
  • Counter ↔ Badge relationship documented. v2.0: Closed — Counter is numeric (a count or progress); Badge is a status or tag label (Success, Premium). Teams pick by whether the content is a number. No further action. (Docs) C4 · Native Mappability
  • Disabled variant width evened up. v2.1: State=Disabled, hasLimit=True went from 61 × 24 to 53 × 24, matching its Default sibling for identical content; the component set narrowed from 109 to 101. Achieved by removing the Overflow frame from the slash-format variants rather than excluding it from layout. Instances no longer jump 8px when switching state. (C1) C1 · Layer Structure & Naming
  • Count and separator layers renamed. v2.1: Applied — all four count layers are now Count (4675:21499 · 4675:21503 · 4675:22735 · 4675:21509) and both slash glyphs are Separator (4675:21500 · 4675:21504). The property surface is legible for the first time. Two limit layers were misnamed in the same sweep — tracked as an open issue. (Rename) C1 · Layer Structure & Naming
  • Overflow glyph layers renamed to Plus. v2.2: 4681:19238 and 4681:19235 went from #overflow-value to Plus — PascalCase, no hash prefix, per the Property Naming Guidelines. Every layer in the two circle variants now carries a correct semantic name. (C2) C2 · Variant & Property Naming
  • Text layer naming complete. v2.3: 4675:21501 and 4675:21505 renamed to Limit, resolving the duplicate-Count collision in the slash-format variants. Every text layer in the set now carries a correct, distinct semantic name — Count ×4, Separator ×2, Limit ×2, Plus ×2 — verified by characters, not position. Closes the C1 naming issue opened at initial assessment. (C1) C1 · Layer Structure & Naming
  • Container renamed to LimitGroup. v2.4: 4675:23030 and 4675:23007 renamed from the generic Container to LimitGroup. Every frame and text layer in the set now carries a semantic name — C1 is fully clean. (C1) C1 · Layer Structure & Naming
  • Text properties confirmed exposed. v2.4: Closed on owner confirmation — Count and Limit are exposed as text properties, so consumers set values without detaching. This closes the "hardcoded text" issue raised at initial assessment. Not independently verifiable from the read-only assessment tooling, which cannot read component property definitions. (C2) C2 · Variant & Property Naming
  • Overflow layer binding confirmed. v2.4: Closed on owner confirmation — the Overflow frames in the two hasLimit=False circle variants (4681:19237 · 4681:19234) are property-bound, not manual visibility overrides. Their removal from the slash-format variants in v2.1 was deliberate, and resolves the nonsensical 0 / 10+ rendering. Clamping stays in code. (C5) C5 · Interaction State Coverage
Variants
Empty — with limit
DES DEV

Slash format showing zero progress against a limit ("0 / 10"). Muted label on neutral bg. Used when no slots are filled yet.

0 / 10
Properties
State
With Limit
Count
Limit
Properties
state empty
with limit yes
Example text 0 / 10
Colors
Background #EEF2F9
Label #C2CFE5
Layout
Height 24
Padding 0 × 8 (hug width)
Corner radius 99 (pill)
Example width 53 (for "0 / 10")
Typography
Style Primary/Label/Small
Font Proxima Soft Bold
Size / line-height 14 / 14
Letter-spacing +0.25
Alignment center
Empty — Colors

Counter at zero — neutral grey chip with muted label.

Role Token Default
Background counter/color/empty/bg #EEF2F9
Label counter/color/empty/label #3C4A5C
Filled — with limit
DES DEV

Slash format with a filled count ("10 / 10"). Brand-blue label on neutral bg. Used when capacity is at or approaching the limit.

10 / 10
Properties
State
With Limit
Count
Limit
Properties
State Filled
Has limit Yes
Char count 120 / 200
Colors
Counter color #3C4A5C
Limit color #3C4A5C
Separator color #3C4A5C
Layout
Padding (top) 4
Alignment right
Gap 0
Typography
Style Caption/Regular
Font Proxima Soft
Size 12
Line-height 16
Filled — Colors

Counter showing a numeric value on the same surface.

Role Token Default
Label main/counter/label #3C4A5C
Background counter/color/empty/bg #EEF2F9
Single integer
DES DEV

Standalone count — notifications, unread messages, pending items. Hugs tightly around the digit (24 × 24 for single digit, grows for 2+ digits). Empty state shown muted; filled state shown in brand-blue. Pairs with overflow handling ("99+") once <code>count</code> is parameterized.

5
Properties
State
With Limit
Count
Limit
Properties
with limit no
state empty | filled
Example text 0
Colors
Empty bg #EEF2F9
Empty label #C2CFE5
Filled bg #EEF2F9
Filled label #072592
Layout
Min-width 24 (circle for single digit)
Max-width hug (grows with digit count)
Padding 0 × 8
Typography
Label style Primary/Label/Small
Label font Proxima Soft Bold · 14 / 14 · +0.25
Active — Colors

Active counter highlight (e.g. unread or pending).

Role Token Default
Background counter/color/active/bg #EEF2F9
Label counter/color/active/label #005CE5
Property Mapping
Figma PropertySwiftUICompose
(hardcoded text "0 / 10", "10 / 10") count: Int count: Int
with limit: yes | no limit: Int? (nil = single-integer format; set = slash format) limit: Int?
state: empty | filled derived from count (0 = empty, >0 = filled) auto, with override
(not modeled) maxDisplay: Int = 99 maxDisplay: Int = 99
Accessibility
RequirementiOSAndroid
Context-aware label Set .accessibilityLabel("5 unread messages") — screen readers should hear what the number means, not just the digits. Set contentDescription = "5 unread messages".
Zero state When count == 0, default behavior (hideWhenZero: true) removes the pill from the accessibility tree entirely. Best practice — nothing to announce. Same — hidden at zero by default.
Overflow Announce the actual count, not "99+" — e.g. "247 unread". The "99+" is a visual truncation, not the truth. Same — screen reader gets the real number.
Contrast Filled: #072592 on #EEF2F9 = 11.8:1 ✓. Empty: #C2CFE5 on #EEF2F9 = 1.4:1 — fails AA. Empty is decorative (shown only when the user opts out of hideWhenZero); don't use for counts that must be read. Same ratios apply.
Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Ready Clean one-layer structure (container + label).
C2 Variant & Property Naming Ready hasLimit + State follow the naming guidelines; Count and Limit are exposed as text properties.
C3 Token Coverage Ready Surface + label bound to main/counter/color/*.
C4 Native Mappability Ready Maps to a tiny EBCounter view/composable — Text inside a Capsule.
C5 Interaction State Coverage Ready Display-only — no interactive states needed. Overflow affordance is property-bound and the clamp rule is settled.
C6 Asset & Icon Quality Not Applicable No assets.
C7 Code Connect Linkability Not Mapped Blocked until the native library exists. State → enum, hasLimitBool, Count/Limit → text parameters.
Variants Inventory (4 total)

state (2) × with limit (2) = 4 variants. Both formats are kept — they solve different problems: single-integer for counts, slash for progress.

#Nodestatewith limitFormatExampleDimensions
118482:71322emptyyesslash0 / 1053 × 24
218482:71324filledyesslash10 / 1059 × 24
318482:71326emptynosingle integer025 × 24
418482:71328fillednosingle integer024 × 24
1.0.0 — April 2026Major
Initial Assessment · node 18482:71321
Verdict: Fix — Keep both formats (single integer + slash). Rename with limithasLimit, parameterize count + limit, add 99+ overflow. Variant count stays at 4. Open
Schema
C2 — Boolean namingwith limit: yes/nohasLimit: true/false. Direct Swift Bool / Kotlin Boolean mapping. Open
C2
C2 — Parameterize values — Expose count: Int + limit: Int?; drop hardcoded text. Derive state from count. Open
C2
C5 — Overflow — Add maxDisplay (default 99); counts beyond render "99+" in single-integer format, and clamp in slash format. Open
C5
C7 — Code Connect — Trivial once parameterization + rename land. Open
C7