ConsolidateRequires Rework
Text Area Component link

A multi-line text input for longer-form entry — label, body, and character counter.

Consolidate into Input Field
Text Area duplicates Input Field's State × isFilled schema with identical tokens (renamed under main/text-area/*). SwiftUI exposes multi-line via axis: .vertical on TextField; Compose exposes it via singleLine=false. Fold into Input Field with a multiline / lineLimit prop so the DS maps 1:1 to the native primitive.
In Context

Typical mobile contexts: feedback forms, message composers, notes, support request descriptions.

Live Preview
Placeholder
Properties
state
isFilled
isExpandable
DS Health
Reusable
Warn
Works anywhere multi-line text is needed, but duplicates Input Field's State × isFilled schema. Reuse is better served by extending Input Field with a multiline flag than by shipping a parallel component.
Self-contained
Partial
Carries its own border, fill, and text styles per state. No label slot, no helperText/error-message slot, no characterCount slot — validation and labeling are pushed onto every consuming screen.
Consistent
Warn
isFilled=yes/no (C2, same anti-pattern Input Field already fixed). state=active instead of focused matches Input Field but diverges from the broader DS verb set. Tokens duplicated under main/text-area/* with identical values to main/input-field/*.
Composable
Partial
Nests in form layouts, but has no sibling wrapper (no Labeled Text Area) and no slot contract for icons or character count. The expand-icon frame holds a fixed raster glyph rather than a swappable node.
Behavior
State iOS Android Figma Property Notes
Default Yes Yes state=default 1px #D7E0EF border, white bg. Resize glyph shown.
Active (Focused) Yes Yes state=active 2px #005CE5 border. Should rename to focused to match platform vocabulary.
Error Yes Yes state=error 2px #D61B2C border. No inline error-message slot.
Disabled Yes Yes state=disabled #EEF2F9 bg, border hidden, text #C2CFE5.
Open Issues
  • Boolean property uses Yes/No. isFilled=yes/no cannot map to Swift Bool or Kotlin Boolean without a translation layer. Input Field already fixed this — Text Area should follow. C2 · Variant & Property Naming
  • Desktop resize-handle glyph baked into a mobile component. The text-area icon (12×12px, bottom-right) mirrors the browser-only resize: both affordance. Native TextField(axis: .vertical) / OutlinedTextField(maxLines = n) auto-grow without a user-facing handle — the glyph has no native equivalent and should not ship in mobile variants. C4 · Native Mappability
  • Resize handle is a raster PNG, once per state. Four separate PNG assets are referenced for the same 12×12px glyph. Even if the handle survives, it should be a single vector instance tinted by main/text-area/color/{state}/icon-resizer. C6 · Asset & Icon Quality
  • No label or helperText slot. Labels and validation messages are handled by the consumer, so every screen re-implements the anatomy. Native multi-line text fields expose both as first-class parameters. C5 · Interaction State Coverage
  • No characterCount / limit affordance. Multi-line entry is the canonical use case for character limits (comments, reviews, message composers). There is no count slot and no maxLength hook — the DS cannot represent limit state today. C5 · Interaction State Coverage
  • Tokens duplicated under main/text-area/*. Every value in main/text-area/color/* mirrors main/input-field/color/* exactly. If Text Area folds into Input Field, this namespace collapses; if it stays, the two token sets should alias a shared main/field/* collection to prevent drift. C1 · Layer Structure & Naming
  • Code Connect mappings not registered. Blocked by property naming and the multi-line-vs-Input Field decision. Cannot register until the family shape is finalized. C7 · Code Connect Linkability
Design Recommendations
  • Fold Text Area into Input Field as a multiline / lineLimit prop. SwiftUI models this as TextField(text:, axis: .vertical).lineLimit(3...6); Compose models it as OutlinedTextField(singleLine = false, maxLines = 6). Both are the same primitive with a single flag. Mirroring that in Figma collapses 8 variants into 0 net new variants on Input Field (add a multiline boolean to the existing 8-variant matrix) and removes the duplicated token namespace. Family
  • Rename isFilled to use true/false. Same fix Input Field already shipped in 1.1.0. Required for Swift Bool / Kotlin Boolean mapping. Rename
  • Rename state=active to state=focused. Matches SwiftUI @FocusState and Compose FocusRequester vocabulary. Apply to Input Field and the whole Form Elements family at once so the rename lands once. Rename
  • Drop the desktop resize handle on mobile variants. If Text Area survives as a sibling, remove the expand-icon frame — it has no native equivalent on iOS/Android. Keep it only if a web/desktop DS variant is in scope, gated behind a platform axis. Asset
  • Add a helperText slot and a characterCount slot beneath the field. Multi-line is the canonical character-count surface. Expose a supporting-text row that can host either error copy, hint copy, or a count — matching Material 3's supportingText / counter pattern. If Text Area folds into Input Field, this slot lives on Input Field and serves both single- and multi-line. Slot
  • Alias main/text-area/* to a shared main/field/* collection. If the family stays split for any reason, the two token sets must reference a single source so border/bg/placeholder/disabled colors never drift. Preferable outcome: delete main/text-area/* outright after consolidation. Token
Styles
Default
DES DEV

Idle state with gray border. Resize-handle glyph sits in the bottom-right regardless of fill.

Placeholder
Properties
isFilled
isExpandable
Properties
state Default
isFilled no
isExpandable true
Colors
Bg #FFFFFF
Border #D7E0EF
Text #0A2757
Placeholder #90A8D0
Layout
Min height 120px
Padding H 12px
Padding V 14px
Border radius radius/radius-2 (6px)
Border 1px solid
Resize vertical, snap to line height
Typography
Value style Primary/Label/Light/Small
Value font Proxima Soft Semibold · 14 / 14 · +0.25
Colors by State

All four color roles are bound to main/text-area/color/{state}/* tokens. Every value mirrors the equivalent main/input-field/color/* token — motivation for consolidation.

Role Token DEFAULTACTIVEERRORDISABLED
Border text-area/color/{state}/border #D7E0EF #005CE5 #D61B2C hidden
Background text-area/color/{state}/bg #FFFFFF #FFFFFF #FFFFFF #EEF2F9
Text (filled) text-area/color/{state}/text #0A2757 #0A2757 #0A2757 #C2CFE5
Placeholder text-area/color/{state}/placeholder #C2CFE5 #C2CFE5 #C2CFE5 #C2CFE5
Resize glyph text-area/color/{state}/icon-resizer #D7E0EF #D7E0EF #D7E0EF #D7E0EF
Active (Focused)
DES DEV

Focused state with 2px blue border. Rename target: <code>focused</code>.

Placeholder
Properties
isFilled
isExpandable
Properties
state Active
isFilled no
isExpandable true
Colors
Bg #FFFFFF
Border #005CE5
Text #0A2757
Placeholder #90A8D0
Layout
Min height 120px
Padding H 12px
Padding V 14px
Border radius radius/radius-2 (6px)
Border 1px solid
Resize vertical, snap to line height
Typography
Value style Primary/Label/Light/Small
Value font Proxima Soft Semibold · 14 / 14 · +0.25
Error
DES DEV

Validation error state with 2px red border. No inline error-message slot — copy is the consumer's responsibility.

Placeholder
Properties
isFilled
isExpandable
Properties
state Error
isFilled no
isExpandable true
Colors
Bg #FFFFFF
Border #D61B2C
Text #0A2757
Placeholder #90A8D0
Layout
Min height 120px
Padding H 12px
Padding V 14px
Border radius radius/radius-2 (6px)
Border 1px solid
Resize vertical, snap to line height
Typography
Value style Primary/Label/Light/Small
Value font Proxima Soft Semibold · 14 / 14 · +0.25
Disabled
DES DEV

Non-interactive state with gray fill and muted text. Border hidden.

Placeholder
Properties
isFilled
isExpandable
Properties
state Disabled
isFilled no
isExpandable true
Colors
Bg #EEF2F9
Border #D7E0EF
Text #90A8D0
Placeholder #C2CFE5
Layout
Min height 120px
Padding H 12px
Padding V 14px
Border radius radius/radius-2 (6px)
Border 1px solid
Resize vertical, snap to line height
Typography
Value style Primary/Label/Light/Small
Value font Proxima Soft Semibold · 14 / 14 · +0.25
Installation Planned API

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.

Property Mapping
Figma PropertySwiftUICompose
(text content) text: Binding<String> value: String
isFilled (yes/no)
(multi-line default) axis: .vertical singleLine = false
(auto-grow range) .lineLimit(3...6) maxLines = 6
state = default
state = active @FocusState interactionSource
state = error .ebError(true) isError = true
state = disabled .disabled(true) enabled = false
isExpandable
SwiftUI
ios/Components/FormElements/EBInputField.swift
Jetpack Compose
android/components/form/EBInputField.kt
Usage Snippets Planned API
Multi-line (default)
EBInputField("Tell us more", text: $value, axis: .vertical)
    .lineLimit(3...6)
EBInputField(
    value = text,
    onValueChange = { text = it },
    placeholder = "Tell us more",
    singleLine = false,
    maxLines = 6
)
Error
EBInputField("Tell us more", text: $value, axis: .vertical)
    .lineLimit(3...6)
    .ebError(true)
EBInputField(
    value = text,
    onValueChange = { text = it },
    placeholder = "Tell us more",
    singleLine = false,
    maxLines = 6,
    isError = true
)
Disabled
EBInputField("Tell us more", text: $value, axis: .vertical)
    .lineLimit(3...6)
    .disabled(true)
EBInputField(
    value = text,
    onValueChange = { text = it },
    placeholder = "Tell us more",
    singleLine = false,
    maxLines = 6,
    enabled = false
)
Accessibility
RequirementiOSAndroid
Minimum touch target 44 x 44 pt (per-line height 22pt, container ≥44pt) 48 x 48 dp
Accessibility label .accessibilityLabel("Comment") contentDescription
Error announcement VoiceOver reads error via .accessibilityValue TalkBack reads error via semantics { error() }
Character-count announcement Announce remaining via .accessibilityValue when a limit is set Expose via supportingText semantics
Usage Guidelines

Do

Use for free-form responses expected to exceed one line — feedback, comments, messages, notes.

Don't

Use for short structured inputs (name, phone, code) — Input Field's single-line default is more appropriate and faster to fill.

Do

Pair with a visible label above the field and a helper-text row below for character counts or format hints.

Don't

Rely on the desktop resize handle on mobile — mobile fields auto-grow within lineLimit/maxLines and the handle has no native behavior.

Criteria Scorecard
ID Criterion Status Notes
C1 Layer Structure & Naming Needs Refinement Duplicate token namespace main/text-area/* mirrors main/input-field/* exactly. Text layer structure is clean.
C2 Variant & Property Naming Requires Rework isFilled=yes/no (same anti-pattern Input Field already resolved). state=active should be focused.
C3 Token Coverage Ready All colors bound to main/text-area/color/*. Spacing and radius tokens resolved.
C4 Native Mappability Requires Rework Exists as a distinct component but native platforms treat multi-line as a single TextField with axis: .vertical / singleLine=false. Desktop resize handle has no native equivalent.
C5 Interaction State Coverage Needs Refinement All 4 interaction states present. Missing slots: label, helper/error text, character count.
C6 Asset & Icon Quality Requires Rework Resize glyph is a raster PNG referenced four times (once per state) instead of a single vector instance.
C7 Code Connect Linkability Not Mapped Blocked by the consolidation decision and property renames.
Code Connect
Aspect Status Notes
Property naming Requires Rework isFilled=yes/no cannot map to native booleans
Component identity Requires Rework Native platforms have no standalone TextArea primitive; consolidation into Input Field is required first
Native component file Needs Refinement Proposed target: EBInputField with multi-line flag
Variants Inventory (8 total)

4 state values × 2 isFilled values.

stateisFilledHeightNode ID
defaultyes62px3070:21242
defaultno46px3070:21239
activeyes62px3070:21243
activeno46px3070:21238
erroryes62px3070:21244
errorno46px3070:21240
disabledyes62px3070:21241
disabledno46px3070:21237
1.0.0 — April 2026Major
Initial Assessment · node 3070:21245
Component assessed — 8 variants documented across state (default/active/error/disabled) × isFilled (yes/no). Multi-line sibling of Input Field within the Form Elements group. Documented
Initial
Consolidation proposed — Fold Text Area into Input Field via a multiline / lineLimit prop to match SwiftUI axis: .vertical and Compose singleLine=false. Open
Family
Boolean property uses Yes/NoisFilled=yes/no instead of true/false. Same anti-pattern Input Field already resolved. Open
C2 Open
Desktop resize-handle glyph — 12×12px raster PNG in the bottom-right has no native mobile equivalent; iOS/Android auto-grow without a user-facing handle. Open
C4, C6 Open
Duplicate token namespacemain/text-area/color/* values mirror main/input-field/color/* exactly; candidate for aliasing or deletion after consolidation. Open
C1 Open
Code Connect mappings — No CLI mappings registered yet. Blocked by consolidation decision and property renames. Open
C7 Open