Textarea
betav0.1.0Multi-line text field for forms. Standalone component built on a native <textarea> with integrated label, required marker, info tooltip trigger and helper/error text. Sized in lines: `rows` is the primary API (the Figma node draws 3), with `minRows`/`maxRows` enabling autosize instead. Replaces MUI's `<TextField multiline>` — the only multi-line surface either product uses, since neither authors `TextareaAutosize`. Deliberately narrower than Input: no success state, no character counter and no icon slots, because the Figma node draws none of them. No resize handle is drawn — the browser's native one is the affordance, and the `resize` prop configures it; it defaults to `both`, the UA default, so a field that does not pass it behaves as it always has.
Variants
Examples
<Textarea label="Description" placeholder="Describe the incident" rows={3} /><Textarea label="Summary" required helperText="Shown on the report header" /><Textarea label="Notes" minRows={2} maxRows={8} placeholder="Grows as you type" /><Textarea label="Runbook" resize="none" placeholder="Not resizable" /><Textarea label="Justification" error="A justification is required" /><Textarea label="Locked" value="Read by the pipeline" disabled onChange={() => {}} />Props
| Prop | Type |
|---|---|
value | string — Controlled value |
defaultValue | string — Default value (uncontrolled) |
onChange | (event: ChangeEvent<HTMLTextAreaElement>) => void — Fires on each keystroke |
label | string — Visible label above the field. Omit → aria-label or aria-labelledby required |
required | boolean — Sets aria-required always; renders the `*` marker only when `label` is also set, since the marker is label-row anatomy (default: false) |
infoTooltip | ReactNode — Info trigger shown next to the label (caller supplies icon/tooltip and its own aria-label); only renders when `label` is set. Its tone follows the field state — icon/info at rest, icon/disabled, icon/error — applied to the wrapper and inherited through currentColor, so any glyph drawn with currentColor (every FDS <Icon>) follows automatically. A child that paints itself — a raster image, or vector markup carrying a literal fill attribute — will not |
placeholder | string — Placeholder shown when empty |
helperText | ReactNode — Helper text below the field; replaced by `error` when set |
error | string — Error message. String only (no boolean) — sets aria-invalid and turns the border, the helper, the label and the required `*` error-toned — the same breadth as Input |
rows | number — Visible height in lines. Primary sizing API (default: 3, the value the node draws). Ignored while `minRows`/`maxRows` is set |
minRows | number — Growth floor in lines; enables autosize. Mutually exclusive with `rows` |
maxRows | number — Growth ceiling in lines; the field scrolls past it. Enables autosize. Mutually exclusive with `rows` |
resize | "none" | "horizontal" | "vertical" | "both" — Browser resize handle (default: "both", the UA default) |
disabled | boolean — Disabled state (default: false) |
className | string — Additional CSS classes on the outer wrapper |
Accessibility
Native <textarea>: the label is a real <label for>, `error` sets aria-invalid and links its message through aria-describedby, and a consumer's own aria-describedby is merged rather than replaced. Enter inserts a newline and never submits; Tab leaves the field. Two pairs are deliberately NOT declared above, both reported to design rather than compensated: (1) the disabled placeholder, --text-input-disabled on --bg-input-disabled, measures 4.35:1 dark / 3.69:1 light — identical values to Input's disabled field, where it is equally undeclared; it is exempt under WCAG 1.4.3 (inactive user interface component) but nobody has written that exemption down in either component, so declaring it here alone would misrepresent the library's actual position. (2) the node's resize grabber, --bg-elevation-default on --bg-input-default at 1.22:1 dark / 1.13:1 light, is not drawn at all: design exemption signed by Sandy 2026-08-26, it is a decorative cut-out behind the browser's native handle and out of 1.4.11's scope. See Textarea.figma.json sharedNotes.