Textarea

Takes several lines of text and grows with them.

Examples

Agent instructions

33 left

Near the character limit

Up to 280 characters.

An optional note with a hint

Shown to whoever takes the conversation next.

Locked while a release is live

Roll back the release to edit these.

Height

  • three rowsdefault

  • one row

Corner

  • fixeddefault

  • resizable

States

  • rest

  • hover

  • focus-visible

  • read-only

  • disabled

  • invalid

  • 33 over the 80 limit

    Over the 80 character limit

    over limit

Usage

When to use it
Use
The answer runs past one line: instructions, a description, a note, a handoff message.
Use
Line breaks matter, like a list of steps or a pasted email thread.
Not for
The answer fits on one line. Use Input.
Not for
The text is an agent prompt with mentions and slash commands. Use Prompt input.

Rules

8 rules
Must
Use limit, not maxLength. Because maxLength cuts a long paste without a word, while limit keeps every character and counts how far over it is.
Should
State the limit in FieldDescription; the counter appears only at 80%.
Must
Name the textarea with FieldLabel or aria-label. Because a screen reader announces an unnamed text area, and the placeholder is gone once the person types.
Must
Size with minRows and maxRows; never a fixed h- class. Because a fixed height stops the growth from minRows to maxRows, so a long note scrolls inside a short box.
Should
Set maxRows between 5 and 12 for text that can run long.
Should
Write the placeholder as one real example sentence under 100 characters.
Never
Add your own aria-live counter to a Textarea with limit. Because it speaks on every keystroke, on top of the 80% and over-limit crossings the Textarea already announces.
Never
Submit a form on Enter in a Textarea; Enter adds a line. Because people press Enter for a new paragraph, so the form submits a half-written note.

Accessibility

6 checks
The textarea is a multi-line textbox with aria-invalid and aria-describedby to the description, error and counter.
The counter is sr-only under 80% of limit and linked by aria-describedby.
A polite status region announces only the crossings: near the limit and over it.
Enter adds a line and never submits; Tab leaves and inserts no tab character.
Text is 16px on coarse pointers so iOS does not zoom.
Forced colors draw a 1px system border; the over-limit words carry the state.

Edge cases

10 edge cases
2,000-character paste or long URL
Grows to maxRows then scrolls inside; an unbroken URL wraps anywhere.
One character
Sits in a three-line box; it never shrinks below minRows.
Container 120px
The box fills the width and the counter wraps under it.
Right to left
Text aligns right and the counter sits at the inline end.
Zoom 200%
Heights are in lh, so three lines stay three lines as the text grows.
In a well
Stays paper with its control edge, so it reads on the grey.
Empty or whitespace only
Empty shows the placeholder; whitespace counts toward the limit.
Held key past the limit
Every character stays and the counter keeps pace; the region speaks only on crossing.
Failed submit
Keep every character.
Reduced motion
Growth is a cut, not a tween.

API

6 props
minRows
number default 3
maxRows
number default 12
limit
number
resizable
boolean default false
onValueChange
(value: string) => void
className
string

Tokens

17 tokens
--line-control
oklch(var(--ink-c) / 0.16)
--radius-soft
6px
--type-label
400 14px/16px var(--font-sans)
--space-2
8px
--line-frame
oklch(var(--ink-c) / var(--line-frame-alpha))
--dur-fast
120ms
--fade-edge
24px
--line-focus
2px
--focus-halo
0 0 0 3px oklch(var(--ink-c) / 0.08)
--border-focus
var(--ink)
--focus-offset
2px
--accent-wash
var(--surface-selected)
--accent-mark
var(--ink)
--type-label-sm
400 12px/16px var(--font-sans)
--text-3
oklch(var(--ink-c) / 0.66)
--text-1
var(--ink)
--fail-text
oklch(51% 0.180 26)

Install

For your coding agent

GitHub

Please star me pookie

141

A new design system every week

Leave your email before you copy the prompt.