Skip to content

Text Input

Form InputsSince 0.2.0
import { TextInput } from '@absoluteui/components/text-input';
import '@absoluteui/components/text-input/style.css';

Using Angular? See Text Input for Angular.

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.

  • 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.
  • 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.
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);
});
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' });
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();
});
}
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' });
<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>
TextInput.create(host: HTMLElement, options: TextInputOptions): TextInput

Global configuration key: textInput (see Configuration).

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.
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.
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.
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).

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.
Slot Default icon
error alert-circle
reveal eye
conceal eye-off

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

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 }

Pattern: Native <input> with a <label for> association (HTML).

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)
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.

Criterion Level Note
1.3.1 Info and Relationships A
1.3.5 Identify Input Purpose AA
1.4.3 Contrast (Minimum) AA
1.4.11 Non-text Contrast AA
2.1.1 Keyboard A
2.4.7 Focus Visible AA
2.5.3 Label in Name A
3.3.1 Error Identification A
3.3.2 Labels or Instructions A
3.3.3 Error Suggestion AA
4.1.2 Name, Role, Value A
4.1.3 Status Messages AA

Automated test results: Accessibility and compliance.

  • 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.

default, focus-visible, filled, disabled, read-only, required, invalid (message shown), over limit, password revealed.

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
  • The required asterisk is aria-hidden; the native required attribute 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).

Full width of its container. Addons do not wrap; the input shrinks. Density tokens change the control height.

Logical properties throughout. The prefix is at the inline start and the suffix at the inline end.

Colors come from role tokens only. Verified in the light, dark, and high-contrast themes. In forced-colors mode, focus draws a Highlight outline.

configureAbsoluteUI({ components: { textInput: { validationTiming: 'input' } } });

Changes apply to existing instances immediately.

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).

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.

No persistence, network access, or telemetry. The native input carries the value for form submission when name is set.

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.

1,000 inputs per page in the performance test. Values of any length; counters count code points.

  • Pasting text longer than maxLength keeps the text and shows the over-limit count and message.
  • '😀😀' has length 2 (code points), matching what users see.
  • An invalid pattern throws FIELD_PATTERN at construction.
  • type: 'url' requires a scheme: example.com is invalid and https://example.com is valid.
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.

  • maxLength is 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.
  • HTML in the label, help text, addons, or messages.
  • Native maxlength truncation.