Text fields
Text input control — 2 variants (filled, outlined), single-line and multi-line, with label, helper text, error state, leading/trailing icons, character counter. Material parity (`/components/text-fields`).
Spec — Text fields
Facet *isual*do Koder Design. Material parity: https://m3.material.io/components/text-fields.
2 variants
| Variant | Visual | Use |
|---|---|---|
| *illed* | Surface-variant bg + bottom border (accent on focus) | Default — denser, more visual weight |
| *utlined* | Border on all sides + transparent bg | Forms with grouped fields; cleaner on light bg |
Pick one per surface — don't mix in the same form.
Anatomy
[leading icon?] Label (floating) [trailing icon?]
[counter?]
┌──────────────────────────────────────────────────────┐
│ [icon?] Input value here [icon?] │
└──────────────────────────────────────────────────────┘
Helper text or error message [chars/max]- *ontainer* 56 px height (default), 48 px (compact)
- *abel*
body-largefloating (above when focused/filled) - *nput text*
body-large - *elper / error*
body-smallbelow - *ounter*
body-smallright-aligned below (whenmaxLength) - *cons* 24 px, leading + trailing optional
R1 — Label behavior
Two label modes:
- *loating*(default) — label sits inside container at rest;
floats up when focused or has value
- *lways-above*— label permanently above the container
Floating is Material standard; always-above is gnome/carbon_ibm preset convention.
R2 — States
Per interaction/states.kmd:
| State | Filled | Outlined |
|---|---|---|
| Empty (rest) | Label inside container | Label inside container |
| Focused | Label floats up + bottom border accent (2 px) |
Label floats up + border accent (2 px) |
| Filled (has value) | Label stays floated | Label stays floated |
| Hovered | Bottom border darker | Border text-muted darker |
| Error | Border error + helper text becomes error text |
Same |
| Disabled | Opacity 0.38; no interaction | Same |
R3 — Singleline vs multiline
- Single-line: 56 px height default, scrolls horizontally
- Multi-line: starts at 56 px, grows to a max (configurable; default
max 5 lines), then scrolls vertically inside
<input type="text">vs<textarea>semantics in HTML
R4 — Specialized input types
| Type | Modifier |
|---|---|
inputmode="email", autocomplete=email, validation regex |
|
| Number | inputmode="numeric", no spinners (CSS hide), pattern validation |
| Phone | inputmode="tel", mask per locale |
| Password | type="password" + show/hide eye icon (trailing) |
| Search | type="search", ⌘K shortcut hint, clear button (trailing X) |
| Date | Pair with date picker (per future date-pickers.kmd) |
R5 — Helper text + error
Below the input container, single line:
Filled state: "Used for sign-in and password reset" (text-muted)
Error state: "Email must include @" (error color)
Filled + counter:"123/200" (text-muted, right)When error: helper text replaced by error message. Both styled with body-small role. Error must be associated via aria-describedby linking input → error element.
Error format per errors/user-facing-messages.kmd: humanized, specific, no "Invalid" / "Wrong".
R6 — Validation
| Validation type | When |
|---|---|
required |
On submit, not while typing |
| Format regex | On blur (after the user finishes typing) |
| Server-side | On submit; debounced check on blur for sensitive fields (email exists) |
| Real-time (length, char restrictions) | While typing — give immediate feedback |
NEVER validate on first keystroke for format-based rules (annoying; "a" → "Invalid email" before user can type more).
R7 — Leading + trailing icons
- *eading icon* signals input type (mail icon for email, search
icon for search) — decorative, no interaction
- *railing icon* actionable (clear X, show/hide password, voice
input mic, calendar picker open) —
<button>element witharia-label
Tap target on trailing icon: 24 px visible, 40 px hit zone.
R8 — Accessibility
<label for="id">connection MANDATORY (oraria-label/aria-labelledby)- Helper text linked via
aria-describedby - Error linked via
aria-describedby+aria-invalid="true"on the input - Required fields:
aria-required="true"(don't rely on*alone) - Autocomplete attribute set for personal data (email, name, address)
- Screen readers announce label → value → state on focus
R9 — Forbidden patterns
- ❌ Input without visible label (placeholder is NOT a label)
- ❌ Placeholder containing format example ("user@example.com")
shown only until user types — use helper text instead (or both)
- ❌ Custom validation messages that contradict spec
(
errors/user-facing-messages.kmd) - ❌ Inputs that look like text but aren't focusable (use a real
<button>if action) - ❌ Disabling submit until valid (use clear error reveal on submit instead)
R10 — Per-preset variation
| Preset | Variant default |
|---|---|
material3 |
Filled |
gnome |
Outlined |
windows_11 |
Filled |
windows_95 |
3D bevel border (Outlined visually) |
ios_cupertino |
Outlined |
carbon_ibm |
Underline only (lighter than Filled bottom-border) |
shadcn |
Outlined |
brutalist |
Outlined + 3 px thick border |
Cross-link
interaction/states.kmd— hoverfocuserror visualsthemes/color-roles.kmd— accent / error / text-muted bindingserrors/user-facing-messages.kmd— error message formatfoundations/ux-writing.kmd— label + helper text stylefoundations/elements.kmd— Control family