Textarea
Native multiline text entry for notes, descriptions, and longer responses.
Preview
Use Textarea when a value needs multiple lines. Keep its label visible and put instructions below the control. Use Input for short, single-line values.
Include context your team needs to get started.
Installation
pnpm dlx shadcn@latest add http://127.0.0.1:3017/r/textarea.jsonInstalls Textarea source, using your existing cn utility and semantic palette. Field and Button are separate optional items used in these examples. It does not change your theme or install a form library. See the registry guide for local endpoint and update details.
Usage
import { Textarea } from '@/components/ui/textarea';
import { Field, FieldLabel } from '@/components/ui/field';
<Field>
<FieldLabel htmlFor="notes">Notes</FieldLabel>
<Textarea id="notes" name="notes" rows={4} />
</Field>All native textarea props are available, including ref, rows, value, defaultValue, onChange, required, readOnly, and maxLength. Textarea does not store a value or validate it internally.
Rows and resizing
The default is four native rows, with a 64px minimum height. Choose rows for the expected amount of content rather than applying the 24/32/44px single-line control heights. Users can resize vertically without widening the form.
Resizing is disabled here. Longer content scrolls inside the field.
Textarea keeps native row sizing; it does not automatically grow as you type. Longer content scrolls within the control until the user resizes it. A fixed-height version should be used deliberately and must still allow scrolling. The minimum height can make very small row counts taller than requested. Browser chrome and manual resizing can affect the rendered height.
Interaction states
Hover and focus below are pinned using the same utilities as the actual interactions. The examples remain editable except for disabled and read-only states.
Labels stay neutral when invalid. The control border, focus outline, and error message use the destructive color. Descriptions and errors use the 12px / 16px caption role, with a 4px gap between field parts. Textarea uses 14px / 20px text on desktop and 16px text on smaller screens. Its page-colored surface has no shadow; padding is 12px horizontally and 8px vertically, with the default control radius of 4px.
readOnly preserves keyboard focus, copying, and form submission. disabled prevents editing and focus, omits the value from submission, and dims the control. Set data-disabled on Field to dim its label too.
<Field data-disabled>
<FieldLabel htmlFor="locked-notes">Notes</FieldLabel>
<Textarea id="locked-notes" disabled defaultValue="Approved project brief." />
</Field>Character limits
Use native maxLength to limit entry. A controlled value can drive a visible counter; it should explain the limit without replacing the field's label or instructions.
0/160 characters. This demo does not save your text.
The native limit and JavaScript value.length count UTF-16 code units, so some emoji use more than one unit. Avoid a live announcement on every keystroke. Check limits again when processing submitted values in a real product.
Validation
Submit an empty or short brief, then enter at least ten characters and try again. This example uses local validation and sends no data.
Use aria-invalid on Textarea and data-invalid on Field. Connect both instructions and errors with aria-describedby, and focus the first invalid control on submission. The demo uses noValidate on the form for custom feedback; native browser validation is also supported. Validate submitted values on the server in a real application.
With Input Group
Use Input Group for an integrated header, footer, or action. Its InputGroupTextarea composes the same Textarea source. The group supplies the shared border and outline, preventing duplicate focus treatments.
0 of 280 characters. This demo does not save your note.
Input Group now declares Textarea as a registry dependency. When updating an existing group installation, review both sources before accepting the update. Grouped textarea retains its 96px minimum editing area and defaults to three rows; standalone Textarea defaults to four rows.
Accessibility
- Match the visible label's
htmlForto the textarea's ID. - Treat placeholders as examples, not labels.
- Enter inserts a newline; Tab moves to the next control. Do not intercept these keys for ordinary text entry.
- Describe required fields visibly and set
requiredon the control. - Keep error text outside the control and associate it explicitly.
- Preserve user-entered text after validation fails.
- Keep long content scrollable and verify wrapping in narrow layouts.
API
| Prop | Default | Purpose |
|---|---|---|
rows | 4 | Native initial visible row count, subject to the minimum height |
disabled | false | Prevent editing and focus; omit value from submission |
readOnly | false | Keep focus and copying while preventing editing |
aria-invalid | Unset | Apply and announce invalid state |
maxLength | Unset | Native upper limit on value length |
| Native textarea props | — | Includes ref, value/event props, required, minLength, and name |
Based on shadcn Textarea, adapted to Migoy's shared control styling.