Text Input
import { TextInput } from '@absoluteui/components/text-input';import '@absoluteui/components/text-input/style.css';Using Angular? See Text Input for Angular.
What it does
Section titled “What it does”Single-line text entry. TextInput renders a native <input> with its field chrome: label, required indicator, help text, validation message, optional character counter, and text addons. Validation runs in the shared validation engine, so messages are localized and identical in every browser. For passwords it adds a reveal toggle and a clipboard policy.
When to use
Section titled “When to use”- Short free-text values: names, email addresses, URLs, phone numbers, passwords, search terms.
- Fields that need consistent, localized validation messages across browsers.
- Values with a fixed prefix or suffix, such as a URL scheme or a unit.
When not to use
Section titled “When not to use”- Multi-line text: use Textarea.
- Numbers users may step or that need locale-aware parsing: use Number Input.
- Choosing from a known list: use Select, Combobox, or Radio Group.
- Dates and times: use Date Input or Date Picker.
Examples
Section titled “Examples”Required email field
Section titled “Required email field”import { TextInput } from '@absoluteui/components/text-input';
const host = document.createElement('div');document.body.append(host);const email = TextInput.create(host, { label: 'Email', type: 'email', name: 'email', required: true, autocomplete: 'email' });host.addEventListener('aui-change', () => { host.dataset.valid = String(email.validity.valid);});Character counter with custom validation
Section titled “Character counter with custom validation”import { TextInput } from '@absoluteui/components/text-input';
const host = document.createElement('div');document.body.append(host);TextInput.create(host, { label: 'Username', maxLength: 20, showCounter: true, validate: (value) => (value.includes(' ') ? 'Usernames cannot contain spaces.' : null),});Password with reveal toggle and clipboard policy
Section titled “Password with reveal toggle and clipboard policy”import { TextInput } from '@absoluteui/components/text-input';
const host = document.createElement('div');document.body.append(host);TextInput.create(host, { label: 'New password', type: 'password', autocomplete: 'new-password', minLength: 12, clipboard: 'block-copy' });Show messages on first input (Mode B)
Section titled “Show messages on first input (Mode B)”import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { textInput: { validationTiming: 'input' } } });import { TextInput } from '@absoluteui/components/text-input';import '@absoluteui/components/text-input/style.css';
const host = document.querySelector<HTMLElement>('#username');if (host) { const username = TextInput.create(host, { label: 'Username', name: 'username', required: true, maxLength: 20, showCounter: true }); host.addEventListener('aui-change', () => { if (!username.validity.valid) username.reportValidity(); });}More usage
Section titled “More usage”import { TextInput } from '@absoluteui/components/text-input';
const host = document.createElement('div');document.body.append(host);TextInput.create(host, { label: 'Email', type: 'email', name: 'email', required: true, autocomplete: 'email' });Anatomy
Section titled “Anatomy”<div class="aui-field aui-text-input" data-aui-control> (consumer host) <label class="aui-field__label" for=input>Label<span class="aui-field__required" aria-hidden="true">*</span></label> <div class="aui-text-input__control"> <span class="aui-text-input__addon aui-text-input__prefix"> (optional) <input class="aui-text-input__input"> <span class="aui-text-input__addon aui-text-input__suffix"> (optional) <button class="aui-text-input__reveal" aria-pressed> (password only) </div> <div class="aui-field__description"> (optional) <div class="aui-field__counter"> (showCounter) <div class="aui-field__error aui-validation-message"> (when shown)</div>API reference
Section titled “API reference”Factory
Section titled “Factory”TextInput.create(host: HTMLElement, options: TextInputOptions): TextInputGlobal configuration key: textInput (see Configuration).
Options
Section titled “Options”| Option | Type | Default | Description |
|---|---|---|---|
label |
string |
Visible label and accessible name. Required. | |
hideLabel |
boolean |
false |
Visually hide the label; it remains the accessible name. |
type |
'text' | 'email' | 'url' | 'tel' | 'password' | 'search' |
"text" |
Native input type. email and url add type validation. |
value |
string |
"" |
Initial value; also the value restored by reset(). |
name |
string |
Form field name. | |
placeholder |
string |
Supplementary hint; never replaces the label. | |
description |
string |
Help text referenced by aria-describedby. | |
required |
boolean |
false |
Empty value is invalid; shows the required indicator. |
disabled |
boolean |
false |
Disables the input. |
readOnly |
boolean |
false |
Value is focusable and submitted but not editable. |
minLength |
number |
Minimum length in code points. | |
maxLength |
number |
Maximum length in code points (validated, not truncated). | |
pattern |
string |
HTML pattern semantics (anchored, v flag). | |
showCounter |
boolean |
false |
Show remaining/over characters; requires maxLength. |
autocomplete |
string |
Native autocomplete token. Password default: current-password. | |
inputMode |
'none' | 'text' | 'decimal' | 'numeric' | 'tel' | 'search' | 'email' | 'url' |
Virtual keyboard hint. | |
spellcheck |
boolean |
Default true for type text, false otherwise. | |
prefix |
string |
Text addon at the inline start. | |
suffix |
string |
Text addon at the inline end. | |
revealable |
boolean |
true |
Password inputs: show a reveal/hide toggle button. |
clipboard |
'allow' | 'block-copy' | 'block-all' |
"allow" |
Clipboard policy for sensitive values. |
validate |
(value: string) => string | null |
Consumer validation; return a message to mark the value invalid. | |
icons |
Partial<{ error: IconRef; reveal: IconRef; conceal: IconRef }> |
Icon slot overrides. | |
validationTiming |
'blur' | 'input' | 'submit' |
"blur" |
When validation messages first appear; afterwards they update live. Globally configurable. |
locale |
string |
"en-US" |
Message and number-formatting locale. Globally configurable. Inherited from common configuration. |
Properties
Section titled “Properties”| Property | Type | Description |
|---|---|---|
host |
HTMLElement |
Consumer host; its children are owned by the component. |
input |
HTMLInputElement |
The native input. |
value |
string |
Current value. |
name |
string | null |
Form field name. |
label |
string |
Label text. |
disabled |
boolean |
Disabled state. |
validity |
FieldValidity |
{ valid, error, message }; computed on every change. |
dirty |
boolean |
Value differs from the initial value. |
touched |
boolean |
Focus has left the control at least once. |
options |
Readonly<TextInputOptions> |
Current instance options. |
Methods
Section titled “Methods”| Method | Description |
|---|---|
setValue(value: string): void |
Programmatic value (no events); clears an external custom error. |
update(options: Partial<TextInputOptions>): void |
Merge and apply options. |
reportValidity(): boolean |
Show messages now and return validity. |
setCustomError(message: string | null): void |
External error (server, cross-field rule); cleared when the user edits. |
getFormValue(): string |
Value for form serialization. |
focus(): void |
Focus the input. |
reset(): void |
Restore the initial value and clear dirty/touched/submitted state. |
destroy(): void |
Remove rendering, listeners, registration, and subscriptions. |
Events
Section titled “Events”| Event | Detail | Bubbles | Cancelable | Description |
|---|---|---|---|---|
aui-input |
{ value: string; validity: FieldValidity } |
Yes | No | User edited the value. |
aui-change |
{ value: string; validity: FieldValidity } |
Yes | No | User committed the value (native change). |
CSS classes
Section titled “CSS classes”All rules live in the aui.components cascade layer, so application styles override them without specificity battles.
| Class | Purpose |
|---|---|
aui-field aui-text-input |
Host. |
aui-text-input--invalid | --disabled |
State modifiers on the host. |
aui-field__label | __required | __description | __counter | __error |
Shared field chrome. |
aui-text-input__control |
Control boundary (input, addons, reveal button). |
aui-text-input__input |
Native input. |
aui-text-input__addon | __prefix | __suffix |
Text addons. |
aui-text-input__reveal |
Password reveal toggle. |
Icon slots
Section titled “Icon slots”| Slot | Default icon |
|---|---|
error |
alert-circle |
reveal |
eye |
conceal |
eye-off |
Design tokens
Section titled “Design tokens”Tokens this stylesheet reads (verified in CI). Override them in a theme or with the Theme Designer.
--aui-border-width | --aui-color-border | --aui-color-border-strong | --aui-color-disabled-bg | --aui-color-error-fg | --aui-color-focus-ring | --aui-color-hover | --aui-color-surface | --aui-color-surface-sunken | --aui-color-text | --aui-color-text-disabled | --aui-color-text-muted | --aui-control-height-md | --aui-control-padding-x | --aui-duration-fast | --aui-easing-standard | --aui-focus-ring-offset | --aui-focus-ring-width | --aui-font-family-sans | --aui-font-size-md | --aui-font-size-sm | --aui-font-weight-medium | --aui-icon-size-sm | --aui-line-height-normal | --aui-line-height-tight | --aui-radius-md | --aui-space-1 | --aui-space-3
TypeScript definitions
Section titled “TypeScript definitions”type TextInputType = 'text' | 'email' | 'url' | 'tel' | 'password' | 'search';type ClipboardPolicy = 'allow' | 'block-copy' | 'block-all';type ValidationTiming = 'blur' | 'input' | 'submit';interface FieldValidity { readonly valid: boolean; readonly error: ValidationErrorCode | null; readonly message: string }interface TextInputValueDetail { value: string; validity: FieldValidity }Accessibility
Section titled “Accessibility”Pattern: Native <input> with a <label for> association (HTML).
Keyboard
Section titled “Keyboard”| Key | Context | Action |
|---|---|---|
| Tab / Shift+Tab | Any | Moves focus to and from the input, then the reveal button when present. |
| Enter / Space | Reveal button focused | Toggles password visibility. |
| All editing keys | Input focused | Native text editing. |
| Element | Role |
|---|---|
| input | textbox (native), or searchbox for type=search |
| reveal button | button (native), toggle via aria-pressed |
| icons | none (aria-hidden=true) |
ARIA attributes
Section titled “ARIA attributes”| Attribute | Element | Value |
|---|---|---|
aria-describedby |
input | Help text, counter, and visible error message ids, then addon ids |
aria-invalid |
input | “true” only while an error message is shown |
aria-pressed |
reveal button | “true” while the password is shown |
aria-controls |
reveal button | Input id |
The control boundary shows the focus indicator (border in color-focus-ring plus a 1px ring). The reveal button has its own :focus-visible outline.
WCAG 2.2 success criteria addressed
Section titled “WCAG 2.2 success criteria addressed”Automated test results: Accessibility and compliance.
Notes and known caveats
Section titled “Notes and known caveats”- The required asterisk is aria-hidden; required state is conveyed by the native required attribute.
- Errors appear after the first blur by default so users are not interrupted while typing.
- The character count is announced through a polite live region only near or over the limit, 750 ms after typing stops.
- Password visibility changes are announced (Password shown / Password hidden).
- Screen-reader announcement of the counter and reveal state has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Behavior
Section titled “Behavior”States
Section titled “States”default, focus-visible, filled, disabled, read-only, required, invalid (message shown), over limit, password revealed.
State transitions
Section titled “State transitions”| From | Trigger | To |
|---|---|---|
| pristine | user types | dirty; message shown only with validationTiming: 'input' |
| any | focus leaves the host | touched; messages shown (blur timing) |
| any | reportValidity() (for example on form submit) |
submitted; messages shown for every timing |
| invalid (custom error) | user edits | custom error cleared, validity recomputed |
| any | reset() |
initial value; pristine, untouched |
Accessibility notes
Section titled “Accessibility notes”- The required asterisk is
aria-hidden; the nativerequiredattribute conveys the state. - Errors appear after the first blur by default, then update live.
- The counter is announced through a polite live region only near or over the limit, 750 ms after typing stops.
- Password visibility changes are announced.
- Manual screen-reader verification is pending (see Known limitations).
Responsive behavior
Section titled “Responsive behavior”Full width of its container. Addons do not wrap; the input shrinks. Density tokens change the control height.
Right-to-left
Section titled “Right-to-left”Logical properties throughout. The prefix is at the inline start and the suffix at the inline end.
Theming
Section titled “Theming”Colors come from role tokens only. Verified in the light, dark, and high-contrast themes. In forced-colors mode, focus draws a Highlight outline.
Global configuration
Section titled “Global configuration”configureAbsoluteUI({ components: { textInput: { validationTiming: 'input' } } });Changes apply to existing instances immediately.
Component configuration
Section titled “Component configuration”Instance options override global and theme defaults. All options are dynamic.
icons.error (default alert-circle), icons.reveal (default eye), and icons.conceal (default eye-off).
Security
Section titled “Security”All text uses textContent. Validation messages never include the entered value. Password inputs default to autocomplete="current-password" with spellcheck off. clipboard: 'block-copy' blocks copy and cut; 'block-all' also blocks paste. CSP-safe; verified under a strict CSP with Trusted Types enforced.
Data handling
Section titled “Data handling”No persistence, network access, or telemetry. The native input carries the value for form submission when name is set.
Performance
Section titled “Performance”Five listeners per instance (input, change, focusout, and clipboard) and one configuration subscription. Budget: under 1 ms average per TextInput.create across 1,000 instances.
Supported data scale
Section titled “Supported data scale”1,000 inputs per page in the performance test. Values of any length; counters count code points.
Edge cases
Section titled “Edge cases”- Pasting text longer than
maxLengthkeeps the text and shows the over-limit count and message. '😀😀'has length 2 (code points), matching what users see.- An invalid
patternthrowsFIELD_PATTERNat construction. type: 'url'requires a scheme:example.comis invalid andhttps://example.comis valid.
Errors
Section titled “Errors”| Code | Category | Cause |
|---|---|---|
TEXT_INPUT_OPTIONS |
configuration | Missing label, invalid type or lengths, or showCounter without maxLength. |
FIELD_PATTERN |
configuration | pattern is not a valid regular expression. |
Validation (validity.error) |
validation | value-missing, type-mismatch, too-short, too-long, pattern-mismatch, custom. |
A failed construction leaves no rendering, listeners, or subscriptions behind.
Known limitations
Section titled “Known limitations”maxLengthis validated, not truncated.- Grapheme clusters such as flag emoji count as more than one character.
- The clipboard policy is a deterrent, not a security boundary.
- No input masking.
- Screen-reader behavior of the counter and reveal toggle has not yet been manually verified with NVDA, JAWS, and VoiceOver.
Unsupported scenarios
Section titled “Unsupported scenarios”- HTML in the label, help text, addons, or messages.
- Native
maxlengthtruncation.