A form field showing a selected recipient — avatar, name, and contact identifier.
Contexts are illustrative. Final screens will reference actual GCash patterns.
isFilled now uses true/false (C2 fixed). Value layer renamed to #value (C1 fixed) — now consistent with sibling fields.icon-placeholder RECTANGLEs (C6) — not swappable icon instances. Cannot compose different icon actions (phonebook, scan QR) without editing the component.| State | iOS | Android | Figma Property | Notes |
|---|---|---|---|---|
| Default | Yes | Yes | State=Default | Gray #D7E0EF border, white bg. Label + placeholder/value visible. |
| Active (Focused) | Yes | Yes | State=Active | Blue #005CE5 border. |
| Error | Yes | Yes | State=Error | Red #D61B2C border. |
| Disabled | Yes | Yes | State=Disabled | #EEF2F9 bg, border hidden. Muted label and text. |
-
isFilledproperty renamed fromYes/Nototrue/false— now maps directly to SwiftBool/ KotlinBooleanC2 Fixed - Text layer renamed from
#text-placeholderto#value— now consistent with sibling fields (Input Field, Labeled Field) C1 Fixed - Both trailing icons use shared Placeholder component instances — swappable by design. Internal RECTANGLE is the default visual, replaced by designers when consuming the component C6 Closed
- Code Connect mappings not registered. Structural work is complete — registration can proceed against the 8-variant
State × isFilledschema. C7 · Code Connect Linkability
- Replace icon placeholders with swappable icon instances. The two
icon-placeholderRECTANGLEs block instance-swap — phonebook, scan-QR, and other trailing actions can't be dropped in without detaching the master. Slot - Document the 56px height rationale. Recipient Field is taller than the standard 46px form fields because of the two-line label + value layout. Call this out in the DS guidelines so it's not mistaken for a design error. Docs
- Add an
errorMessageslot below the field. Inline validation text keeps the field self-contained and matches the pattern proposed for the other form fields. Slot
Idle state with gray border. Two-line layout: small label above, value/placeholder below. Two trailing icon placeholders.
All states share the same two-line container (56px height, 6px radius). Border color is the primary state indicator. Two trailing icon placeholders use a fixed fill across all states.
| Role | Token | DEFAULT | ACTIVE | ERROR | DISABLED |
|---|---|---|---|---|---|
| Border | field/border | #D7E0EF | #005CE5 | #D61B2C | hidden |
| Background | field/bg | #FFFFFF | #FFFFFF | #FFFFFF | #EEF2F9 |
| Label text | field/label | #0A2757 | #0A2757 | #0A2757 | #90A8D0 |
| Value (filled) | field/text/filled | #0A2757 | #0A2757 | #0A2757 | #90A8D0 |
| Value (empty) | field/text/placeholder | #90A8D0 | #90A8D0 | #90A8D0 | #C2CFE5 |
| Icon placeholder | field/icon | #C2C6CF | #C2C6CF | #C2C6CF | #C2C6CF |
Focused state with blue border indicating active input.
Validation error state with red border.
Non-interactive state with gray background and hidden border. Muted label and text colors.
iOS — Swift Package Manager
// In Xcode: File → Add Package Dependencies "https://github.com/AY-Org/eb-ds-ios"
Android — Gradle (Kotlin DSL)
dependencies { implementation("com.eastblue.ds:form-elements:1.0.0") }
Import
import EastBlueDS // SwiftUI import com.eastblue.ds.form.* // Compose
Package not yet published. These are the planned distribution paths.
| Figma Property | SwiftUI | Compose |
|---|---|---|
| isFilled (true/false) | text: Binding<String> | value: String |
| #label | label: String | label: String |
| #text-placeholder | placeholder: String | placeholder: String |
| icon-group (2x icons) | trailingIcons: [Image] | trailingIcons: @Composable |
| State = Default | — | — |
| State = Active | .focused() | interactionSource |
| State = Error | .ebError(true) | isError = true |
| State = Disabled | .disabled(true) | enabled = false |
EBRecipientField( label: "Mobile Number", text: $recipientNumber, placeholder: "Enter number or name", trailingIcons: [ Image(systemName: "person.crop.circle"), Image(systemName: "qrcode.viewfinder") ] )
EBRecipientField( label = "Mobile Number", value = recipientNumber, onValueChange = { recipientNumber = it }, placeholder = "Enter number or name", trailingIcons = { IconButton(onClick = onContactsClick) { Icon(Icons.Default.Person, "Contacts") } IconButton(onClick = onScanClick) { Icon(Icons.Default.QrCode, "Scan QR") } } )
EBRecipientField( label: "Mobile Number", text: $recipientNumber, placeholder: "Enter number or name" ) .ebError(true)
EBRecipientField( label = "Mobile Number", value = recipientNumber, onValueChange = { recipientNumber = it }, placeholder = "Enter number or name", isError = true )
EBRecipientField( label: "Mobile Number", text: $recipientNumber, placeholder: "Enter number or name" ) .disabled(true)
EBRecipientField( label = "Mobile Number", value = recipientNumber, onValueChange = { recipientNumber = it }, placeholder = "Enter number or name", enabled = false )
| Requirement | iOS | Android |
|---|---|---|
| Minimum touch target | 44 x 44 pt (56px field exceeds) | 48 x 48 dp (56px field exceeds) |
| Accessibility label | .accessibilityLabel("Recipient") | contentDescription |
| Error announcement | VoiceOver reads error via .accessibilityValue | TalkBack reads error via semantics { error() } |
| Trailing icon labels | .accessibilityLabel("Contacts") per icon | contentDescription per icon button |
Do
Use Recipient Field for contact/number entry in money transfer flows (Send Money, Pay Bills, Buy Load). The two-line layout with trailing icons is purpose-built for this context.
Don't
Use Recipient Field for general text input — use Input Field or Labeled Field instead. The 56px height and icon slots add unnecessary weight for simple text entry.
Do
Provide meaningful trailing icons (e.g. contacts picker, QR scanner) that match the field's purpose. Both slots should have distinct actions.
Don't
Leave icon placeholders as-is in production — they are design placeholders only. Always replace with real icon instances before handoff.
| ID | Criterion | Status | Notes |
|---|---|---|---|
| C1 | Layer Structure & Naming | Ready | Layer renamed to #value, now consistent with sibling fields. |
| C2 | Variant & Property Naming | Ready | isFilled=true/false — correctly uses native boolean values. |
| C3 | Token Coverage | Needs Refinement | Colors appear correct but token binding not verified. Icon placeholders use hardcoded #C2C6CF. |
| C4 | Native Mappability | Ready | Maps to custom EBRecipientField (SwiftUI + Compose). Two-line layout with trailing icon slots. |
| C5 | Interaction State Coverage | Ready | All 4 states defined: Default, Active, Error, Disabled. |
| C6 | Asset & Icon Quality | Requires Rework | Both trailing icons are icon-placeholder RECTANGLEs — not swappable icon instances. |
| C7 | Code Connect Linkability | Needs Refinement | No CLI mappings registered yet. |
| Aspect | Status | Notes |
|---|---|---|
| Property naming | Ready | isFilled=true/false — boolean values map directly to native types |
| Layer naming | Requires Rework | #text-placeholder needs rename to #value |
| Icon slots | Requires Rework | RECTANGLE placeholders — need swappable icon instances |
| State coverage | Ready | All 4 states defined |
| Native component file | Needs Refinement | EBRecipientField.swift / EBRecipientField.kt not yet created |
4 State values × 2 isFilled values (true/false).
| State | isFilled | Node ID |
|---|---|---|
| Default | true | 17758:3868 |
| Default | false | 17758:3875 |
| Active | true | 17758:3882 |
| Active | false | 17758:3889 |
| Error | true | 17758:3896 |
| Error | false | 17758:3903 |
| Disabled | true | 17758:3910 |
| Disabled | false | 17758:3917 |
#text-placeholder to #value. Now consistent with sibling fields (Input Field, Labeled Field) for direct native property mapping.
C1 FixedisFilled updated from Yes/No to true/false. Now maps directly to Swift Bool and Kotlin Boolean for Code Connect.
C2 FixedisFilled=Yes/No instead of true/false. Incompatible with Swift Bool and Kotlin Boolean for Code Connect mapping.
Fixed in 1.1.0#text-placeholder instead of #value used by other Form Elements.
Fixed in 1.2.0icon-placeholder RECTANGLEs, not component instances.
Open