Skip to content

Textarea

Form InputsSince 0.2.0
import { Textarea } from '@absoluteui/components/textarea';
import '@absoluteui/components/textarea/style.css';

Using Angular? See Textarea for Angular.

Multi-line text entry. Textarea renders a native <textarea> with the same field chrome and constraint set as Text Input: label, required indicator, help text, validation message, and optional character counter. Validation runs in the shared validation engine, so messages are localized and identical in every browser. resize: 'auto' grows the control with its content.

  • Free text that may span several lines: comments, descriptions, messages, addresses.
  • Long-form values with a length limit that users should see while typing.
  • Fields that need consistent, localized validation messages across browsers.
  • Single-line values such as names or email addresses: use Text Input.
  • Formatted rich text: use Rich Text Editor.
  • Numbers: use Number Input.

Required comments with a character counter

Section titled “Required comments with a character counter”
import { Textarea } from '@absoluteui/components/textarea';
const host = document.createElement('div');
document.body.append(host);
const comments = Textarea.create(host, { label: 'Comments', name: 'comments', required: true, maxLength: 500, showCounter: true });
host.addEventListener('aui-change', () => {
host.dataset.valid = String(comments.validity.valid);
});
import { Textarea } from '@absoluteui/components/textarea';
const host = document.createElement('div');
document.body.append(host);
Textarea.create(host, { label: 'Message', rows: 2, resize: 'auto', maxRows: 8 });
import { Textarea } from '@absoluteui/components/textarea';
const host = document.createElement('div');
document.body.append(host);
Textarea.create(host, {
label: 'Bio',
minLength: 20,
validate: (value) => (/https?:\/\//.test(value) ? 'Links are not allowed in the bio.' : null),
});
import { configureAbsoluteUI } from '@absoluteui/core';
configureAbsoluteUI({ components: { textarea: { validationTiming: 'input' } } });
import { Textarea } from '@absoluteui/components/textarea';
import '@absoluteui/components/textarea/style.css';
const host = document.querySelector<HTMLElement>('#feedback');
if (host) {
const feedback = Textarea.create(host, { label: 'Feedback', name: 'feedback', required: true, maxLength: 1000, showCounter: true, resize: 'auto', maxRows: 10 });
host.addEventListener('aui-change', () => {
if (!feedback.validity.valid) feedback.reportValidity();
});
}
import { Textarea } from '@absoluteui/components/textarea';
const host = document.createElement('div');
document.body.append(host);
Textarea.create(host, { label: 'Message', rows: 2, resize: 'auto', maxRows: 8, maxLength: 500, showCounter: true });
<div class="aui-field aui-textarea" data-aui-control> (consumer host)
<label class="aui-field__label" for=textarea>Label<span class="aui-field__required" aria-hidden="true">*</span></label>
<textarea class="aui-textarea__input" rows>
<div class="aui-field__description"> (optional)
<div class="aui-field__counter"> (showCounter)
<div class="aui-field__error aui-validation-message"> (when shown)
</div>
Textarea.create(host: HTMLElement, options: TextareaOptions): Textarea

Global configuration key: textarea (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.
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 textarea.
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).
showCounter boolean false Show remaining/over characters; requires maxLength.
rows number 3 Visible text rows, integer 1..100; the minimum height for resize ‘auto’.
resize 'none' | 'vertical' | 'auto' "vertical" Native vertical resize handle, fixed height, or grow with content.
maxRows number Upper bound in rows for resize ‘auto’ (integer >= rows); content scrolls beyond it.
autocomplete string Native autocomplete token.
spellcheck boolean true Native spellcheck.
validate (value: string) => string | null Consumer validation; return a message to mark the value invalid.
icons Partial<{ error: 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.
textarea HTMLTextAreaElement The native textarea.
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<TextareaOptions> Current instance options.
Method Description
setValue(value: string): void Programmatic value (no events); clears an external custom error.
update(options: Partial<TextareaOptions>): 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 textarea.
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, on blur).

All rules live in the aui.components cascade layer, so application styles override them without specificity battles.

Class Purpose
aui-field aui-textarea Host.
aui-textarea--invalid | --disabled State modifiers on the host.
aui-textarea--resize-none | --auto | --auto-native Sizing modifiers on the host (–auto-native: field-sizing: content is used).
aui-field__label | __required | __description | __counter | __error Shared field chrome.
aui-textarea__input Native textarea; also the control boundary.
Slot Default icon
error alert-circle

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-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-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-2

type TextareaResize = 'none' | 'vertical' | 'auto';
type ValidationTiming = 'blur' | 'input' | 'submit';
interface FieldValidity { readonly valid: boolean; readonly error: ValidationErrorCode | null; readonly message: string }
interface TextareaValueDetail { value: string; validity: FieldValidity }

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

Key Context Action
Tab / Shift+Tab Any Moves focus to and from the textarea.
Enter Textarea focused Inserts a line break (native).
All editing keys Textarea focused Native text editing.
Element Role
textarea textbox (native, multi-line)
icons none (aria-hidden=true)
Attribute Element Value
aria-describedby textarea Help text, counter, and visible error message ids
aria-invalid textarea “true” only while an error message is shown

The textarea shows the focus indicator (focus-ring-width outline in color-focus-ring, border color, and a 1px ring).

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.
  • Auto-grow keeps the whole value visible up to maxRows, which helps users review what they wrote.
  • Screen-reader announcement of the counter has not yet been manually verified with NVDA, JAWS, and VoiceOver.

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

From Trigger To
pristine user types dirty; message shown only with validationTiming: 'input'
any focus leaves the host touched; messages shown (blur timing), after the pointer is released if focus left by a click
any reportValidity() (for example on form submit) submitted; messages shown for every timing
invalid (custom error) user edits custom error cleared, validity recomputed
auto-grow user types or the value is set height follows content between rows and maxRows
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.
  • Auto-grow keeps the whole value visible up to maxRows, so users can review what they wrote without scrolling.
  • Manual screen-reader verification is pending (see Known limitations).

Full width of its container. Height follows rows. With resize: 'vertical' users can drag the height; with 'auto' the control grows between rows and maxRows and then scrolls. Density tokens change font size and padding; the row bounds use lh units so they follow them.

Logical properties throughout. The native resize handle follows the writing direction.

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

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

Changes apply to existing instances immediately.

Instance options override global and theme defaults. All options are dynamic.

icons.error (default alert-circle).

All text uses textContent. Validation messages never include the entered value. Auto-grow sizing is written through the CSSOM (style.setProperty), never through a style attribute. CSP-safe (no inline styles or HTML sinks).

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

Three listeners per instance (input, change, focusout) and one configuration subscription. With native field-sizing there is no layout work in script; the fallback performs one layout read (scrollHeight) per input event. Budget: under 1 ms average per Textarea.create across 1,000 instances.

1,000 textareas per page is the performance target. Values of any length; counters count code points.

  • Pasting text longer than maxLength keeps the text and shows the over-limit count and message.
  • A line break counts as one character.
  • maxRows without resize: 'auto', or smaller than rows, throws TEXTAREA_OPTIONS.
  • Auto-grow on a textarea that is not connected (or is hidden) is measured on the next input event.
Code Category Cause
TEXTAREA_OPTIONS configuration Missing label; invalid lengths, rows, resize, or maxRows; or showCounter without maxLength.
Validation (validity.error) validation value-missing, too-short, too-long, 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.
  • Without native field-sizing support, a container resize that rewraps text is applied on the next edit.
  • Only vertical resizing is offered.
  • Screen-reader behavior of the counter has not yet been manually verified with NVDA, JAWS, and VoiceOver.
  • HTML in the label, help text, or messages.
  • Rich text, mentions, or syntax highlighting.
  • Native maxlength truncation.