Published · Updated · v0.6.5 · MIT License · Source: text-field.md
Text field
Text field is a single- or multi-line input built on native <input> and <textarea> elements. Use a text field when people must enter or edit free-form text — names, email addresses, search terms. The value must submit through a real <form>. Every visible label is explicitly associated through for and id, while helper and error messages use unique IDs referenced by aria-describedby.
Examples
Outlined and filled
Outlined and filled fields cover the two visual variants of the component.
{{template "text-field" .}}
Native input surface
Type, constraints, and autofill hints pass through as native attributes.
{{template "text-field" .}}
Helper and error messages
Helper text and visible errors are associated through aria-describedby, never color alone.
{{template "text-field" .}}
Server-side validation
The validation form posts to the server and swaps the fragment on HTTP 422.
{{template "validation-form" .}}
API reference
| Prop | Type | Default | Description |
|---|---|---|---|
ID | string | "" | Element id paired with the label's for attribute. |
Label | string | "" | Visible label text, explicitly associated via for and id. |
Name | string | "" | Form submission name. |
Value | string | "" | Initial input or textarea value. |
Variant | string | "" | Field style: outlined or filled. |
Helper | string | "" | Helper message referenced by aria-describedby. |
MessageRole | string | "" | ARIA role for the helper message, for example status. |
Error | string | "" | Error message; renders aria-invalid and a visible alert. |
Disabled | bool | false | Native disabled attribute; takes precedence over error. |
Textarea | bool | false | Renders a multi-line textarea instead of an input. |
Autofocus | bool | false | Native autofocus attribute. |
Type | string | "text" | Native input type: email, url, tel, number, password, search, or text. Inputs only. |
Required | bool | false | Native required attribute; the value must be submitted. |
MaxLength | int | 0 | Native maxlength in characters; 0 omits the attribute. |
MinLength | int | 0 | Native minlength in characters; 0 omits the attribute. |
Pattern | string | "" | Native pattern regex for inputs; textareas do not support it. |
Autocomplete | string | "" | Standard autocomplete token (email, current-password, …). |
InputMode | string | "" | Native inputmode hint for the on-screen keyboard. |
ReadOnly | bool | false | Native readonly attribute; focusable and submitted, not editable. |
Placeholder | string | "" | Visible hint text; keeps the floating label floated and never replaces it. |
Guidance
When to use
Use a text field when people must enter or edit free-form text — names, email addresses, search terms. The value must submit through a real <form>.
When not to use
Do not use a text field when a constrained choice is faster. One option from a known list belongs in a Select or Radio group. An approximate magnitude belongs in a Slider. For short, predefined answers, Chips can replace typing.
Usability
- Single-line inputs use
<input>; longer answers use the multi-line<textarea>. - Every visible label is explicitly associated through
forandid; helper and error messages use unique IDs referenced byaria-describedby. - Server-side validation returns HTTP 422 with the submitted value preserved and
aria-invalid="true"on the field.
Accessibility
- The native
<input>/<textarea>keeps its role, name, value, and keyboard behavior at no cost. - Every visible label is explicitly associated through
forandid, matching what is on screen. - Errors are announced via
aria-invalidplus visible error text — never color alone. - Disabled keeps the native
disabledattribute and takes precedence over error.
See Choose the right control for the cross-component decision.
Alternative names
- Input, text input, form field, entry field.
Agent prompt
Use Text field when people must enter or edit free-form text — names, email addresses, search terms. The value must submit through a real <form>. It is built on native <input> and <textarea> elements. Every visible label is associated through for/id, and helper and error messages are referenced by aria-describedby. Server-side validation returns HTTP 422 with the submitted value preserved, aria-invalid="true", and the X-Gelium-Validation: true header for the HTMX swap hook. Never build a custom text-entry widget: the native control is the contract, disabled keeps the native disabled attribute, and disabled takes precedence over error.
Variants and states
The dogfooded examples demonstrate outlined and filled variants, plus normal and helper text. They include a visibly labelled error that does not rely on color. They cover disabled inputs (filled and outlined), a disabled textarea, and an editable textarea. The preview also dogfoods the native input surface: typed inputs, constraints, autofill hints, and a real placeholder.
Disabled fields keep the native disabled attribute: they leave the tab order, cannot receive focus or edits, and are excluded from hover and focus states. Disabled takes explicit precedence over error: a field flagged disabled never advertises aria-invalid or an error alert, even when both states are set. The CSS also resolves a combined ui-text-field-error ui-text-field-disabled wrapper to the disabled palettes instead of the error palette.
Input surface
Single-line fields map to the native <input>; multi-line ones to the <textarea>. The view passes a set of native attributes through, rendering each only when set.
Typeswitches the input kind:email,url,tel,number,password,search, or the defaulttext. Textareas ignore it, and so doesPattern, which is input-only.InputModehints at the on-screen keyboard. Pair it withTypeper the Forms contract table.Autocompletecarries a standard token for identity and contact data, likeemailorcurrent-password.Required,MaxLength,MinLength, andPatternexpress native constraints. Server validation stays authoritative on submit.ReadOnlykeeps the field focusable and submitted, but not editable. Disabled instead leaves the tab order.Placeholdershows hint text without replacing the visible label. The floating label stays floated so hint and label never overlap.
See Forms contract for the type and inputmode pairing table, autocomplete tokens, and validation timing.
How does server-side validation work?
The form below submits a named field to the server with browser validation disabled so the server remains the source of truth.
Whitespace-only input returns HTTP 422 with the submitted value preserved, aria-invalid="true", and an associated error. Valid input returns HTTP 200 with the preserved value and an accessible success message.
The form works without JavaScript: its native method and action submit to the same endpoint. The endpoint returns a complete documentation page with the updated form, preserving the HTTP 422 or 200 status. HTMX (the progressive-enhancement library that swaps server-rendered fragments) is an optional layer. When it sends HX-Request: true, the server returns only the complete form fragment and replaces it using hx-target="this" plus hx-swap="outerHTML".
Expected HTMX validation failures return X-Gelium-Validation: true. Local /static/app.js listens for htmx:before:swap. It reads the HTMX 4 response from event.detail.ctx.response. For status 422 with that header, it sets shouldSwap to true and isError to false. Other HTTP 422 responses remain transport errors and are not swapped by this hook.