Textarea
Takes several lines of text.
Sizing
rowsdefault
autoGrow
States
rest
focus
4 left
Near the character limitnear limit
6 over the 16 limit
Over the 16 character limitover limit
disabled
read-only
Usage
When to use it
- Use
- The answer runs past one line: a system prompt, instructions, feedback on a run, a reason.
- Use
- The text has a soft length limit the person should see coming (limit).
- Not for
- The answer fits on one line. Use Input.
- Not for
- The person chats with an agent: use the prompt input, which carries send and attachments.
- Not for
- The text is code or JSON to read: show it in a code block.
Rules
7 rules
- Must
- Put a Textarea in a Field with a FieldLabel. Because a placeholder vanishes on the first keystroke and is not a reliable accessible name.
- Must
- Use limit for a length cap, never maxLength. Because maxLength cuts a paste without a word, while limit keeps every character, counts down near the end and marks the field invalid past it.
- Never
- Make a Textarea a pill or change its corner. Because pills are for one line; a box of text takes the 10px overlay corner, and a pill would clip its first and last lines.
- Never
- Draw a ring, a black line or a shadow to show focus. Because a field shows focus by darkening its own line to ink at about a third, and a ring reads as a pressable thing.
- Should
- With autoGrow, set maxRows so a long paste scrolls inside the box instead of pushing the form off the screen.
- Should
- Leave resizable off when autoGrow is on; the box already fits its text. Because a dragged height fights the grown one on the next keystroke.
- Should
- Make the placeholder an example of a good answer, not the label again.
State order
7 states, highest first
- 1
- disabled
- 2
- invalid
- 3
- over-limit
- 4
- focus
- 5
- near-limit
- 6
- read-only
- 7
- rest
Accessibility
4 checks
- A native textarea named by FieldLabel, with aria-invalid and aria-describedby from the Field.
- With limit, the counter joins aria-describedby, and a status region announces only crossing 80% and the limit, never every keystroke.
- Focus darkens the line to --line-focus beside the caret; invalid adds the error sentence, so neither rests on colour alone.
- Text is 16px under a coarse pointer, so a phone browser never zooms on focus.
Keyboard
2 keys
- Enter
- Adds a line; it never submits the form.
- Tab
- Leaves the textarea; it never types a tab.
Edge cases
6 edge cases
- Paste over the limit
- Keeps every character, counts how far over in the failure word and marks the field invalid.
- Long paste with autoGrow
- Grows to maxRows, then scrolls inside the box.
- Browser without field-sizing
- autoGrow measures scrollHeight on every input instead.
- Narrow container
- The width follows the container; only the height follows the text.
- Right to left
- Text and the counter align to the reading direction.
- Dark theme
- Paper turns near-black and the line stays ink at 15%.
API
7 props
rowsnumberdefault3autoGrowbooleandefaultfalseminRows, maxRowsnumberdefault3, 10limitnumberresizablebooleandefaultfalseonValueChange(value: string) => voidaria-invalidboolean
Tokens
18 tokens
--paper- #ffffff
--field- #efefef
--line-control- rgb(5 5 5 / 0.15)
--line-focus- rgb(5 5 5 / 0.32)
--line-faint- rgb(5 5 5 / 0.06)
--fail- #e35e49
--fail-text- #b23c29
--text-1- rgb(5 5 5 / 0.80)
--text-2- rgb(5 5 5 / 0.60)
--text-3- rgb(5 5 5 / 0.45)
--text-disabled- rgb(5 5 5 / 0.32)
--radius-overlay- 10px
--type-body-sm- 400 13px/1.5 var(--font-sans)
--type-caption- 400 12px/1.35 var(--font-sans)
--space-2- 8px
--space-3- 12px
--dur-state- 160ms
--ease-out- cubic-bezier(0.2, 0.8, 0.2, 1)