Textarea
A multi-line text field that the user can resize. Three fills and every state: hover, focus, filled, read-only, disabled and error.
Version 0.4.1 ·
Installation
bunx --bun shadcn@latest add @dga/textareaInstalls Field too.
Usage
import { Field, FieldDescription, FieldLabel } from "@/components/ui/field";
import { Textarea } from "@/components/ui/textarea";
export function DetailsField() {
return (
<Field name="details">
<FieldLabel required>Request details</FieldLabel>
<Textarea required rows={4} />
<FieldDescription>Give the plot number and the street name.</FieldDescription>
</Field>
);
}Use Textarea for answers that need more than a line: descriptions, comments, reasons. Set rows for the starting height. Tell people the limit in the helper text, and do not cut text off silently.
Anatomy
- Textarea (
<textarea>): the border, fill, text and resize handle in one element. - The scroll bar is the browser's own; it appears when the text is taller than the box.
Examples
States
Default, filled, read-only, disabled and error, plus the darker fill without resizing.
Resizing
resize="vertical" (default) shows a handle at the end corner. Use resize="none" when the layout needs a fixed height. The field never resizes sideways.
<Textarea resize="none" rows={6} />RTL
Text starts on the right and the resize handle sits in the bottom-left corner. Everything follows the page direction.
Accessibility
| Key | Action |
|---|---|
| Tab | Moves focus to the field. |
| Enter | Starts a new line. |
- A native
<textarea>linked to its Field label, helper text and error. - Same states as Input: the underline grows from the centre when pressed (half) and focused (full), and there is no outline. A wrapper
<div>carries the border and underline because a<textarea>cannot draw one. - The resize handle can be dragged with a pointer. Keyboard users get the same space by typing; give
rowsenough height for the expected answer. - If you show a character limit, put it in the helper text and use
maxLengthso it is enforced.
API Reference
Textarea
A multi-line text field that grows in height (it is resizable by default). Label it with a Field. It is linked to the Field's label, helper text and error like any other control.
| Prop | Type | Default |
|---|---|---|
"default" | "lighter" | "darker"Fill: `default` (white), `lighter` or `darker`. All three keep a visible border. | "default" | |
| ||
"vertical" | "none"`vertical` lets the user drag the corner to change the height. `none` fixes it. | "vertical" | |
| ||
stringClass names for the box around the field (border, fill and underline). | No default | |
| ||
stringClass names for the native `<textarea>`. | No default | |
| ||
numberVisible lines of text, which sets the starting height. | 4 | |
| ||
stringInitial value when uncontrolled. | No default | |
| ||
booleanDisables the field. | No default | |
| ||
stringHint shown while empty. | No default | |
| ||
booleanThe text can be read and copied but not changed. | No default | |
| ||
booleanThe form cannot be submitted while the field is empty. | No default | |
| ||
stringControlled value. | No default | |
| ||
Also accepts every prop of the Base UI Field (opens in a new tab).
Deviations from DGA
- Figma has one fixed-height variant. This one grows with
rowsand can be resized. - Lighter and darker have no border at rest, as on Input, including the known gap.
| Change | Reason |
|---|---|
Textarea: size | A multi-line field has no single right height. Figma's Resize and Scroll Bar props map to resize and the native scroll bar. |
Contrast
276 pairs checked · all pass WCAG 2.1 AAShow 46 statesHide
| Variant / state | Light | Dark |
|---|---|---|
| filled text | 18.09:1 AAA | 15.87:1 AAA |
| hovered text | 18.09:1 AAA | 15.87:1 AAA |
| focused text | 10.17:1 AAA | 12.04:1 AAA |
| pressed text | 9.24:1 AAA | 9.64:1 AAA |
| pressed placeholder | 6.69:1 AA | 5.06:1 AA |
| pressed prefix and suffix text | 9.24:1 AAA | 9.64:1 AAA |
| underline, focused and pressed | 18.74:1 3:1 | 16.80:1 3:1 |
| placeholder | 4.77:1 AA | 6.32:1 AA |
| prefix and suffix text | 10.17:1 AAA | 12.04:1 AAA |
| icon | 4.77:1 3:1 | 9.38:1 3:1 |
| border, default | 4.57:1 3:1 | 3.80:1 3:1 |
| border, hovered | 9.73:1 3:1 | 12.04:1 3:1 |
| border, focused and pressed | 17.93:1 3:1 | 16.80:1 3:1 |
| underline, error | 4.62:1 3:1 | 4.65:1 3:1 |
| border, error | 4.62:1 3:1 | 4.65:1 3:1 |
| filled text (lighter) | 17.64:1 AAA | 14.42:1 AAA |
| hovered text (lighter) | 17.64:1 AAA | 14.42:1 AAA |
| focused text (lighter) | 10.17:1 AAA | 12.04:1 AAA |
| pressed text (lighter) | 9.24:1 AAA | 9.64:1 AAA |
| pressed placeholder (lighter) | 6.69:1 AA | 5.06:1 AA |
| pressed prefix and suffix text (lighter) | 9.24:1 AAA | 9.64:1 AAA |
| underline, focused and pressed (lighter) | 18.28:1 3:1 | 15.27:1 3:1 |
| placeholder (lighter) | 4.65:1 AA | 5.75:1 AA |
| prefix and suffix text (lighter) | 9.92:1 AAA | 10.95:1 AAA |
| icon (lighter) | 4.65:1 3:1 | 8.52:1 3:1 |
| border, hovered (lighter) | 9.73:1 3:1 | 12.04:1 3:1 |
| border, focused and pressed (lighter) | 17.93:1 3:1 | 16.80:1 3:1 |
| underline, error (lighter) | 4.62:1 3:1 | 4.65:1 3:1 |
| border, error (lighter) | 4.62:1 3:1 | 4.65:1 3:1 |
| filled text (darker) | 16.44:1 AAA | 17.04:1 AAA |
| hovered text (darker) | 16.44:1 AAA | 17.04:1 AAA |
| focused text (darker) | 10.17:1 AAA | 12.04:1 AAA |
| pressed text (darker) | 9.24:1 AAA | 9.64:1 AAA |
| pressed placeholder (darker) | 6.69:1 AA | 5.06:1 AA |
| pressed prefix and suffix text (darker) | 9.24:1 AAA | 9.64:1 AAA |
| underline, focused and pressed (darker) | 17.03:1 3:1 | 18.03:1 3:1 |
| placeholder (darker) | 6.69:1 AA | 6.79:1 AA |
| prefix and suffix text (darker) | 9.24:1 AAA | 12.93:1 AAA |
| icon (darker) | 4.34:1 3:1 | 10.07:1 3:1 |
| border, hovered (darker) | 9.73:1 3:1 | 12.04:1 3:1 |
| border, focused and pressed (darker) | 17.93:1 3:1 | 16.80:1 3:1 |
| underline, error (darker) | 4.62:1 3:1 | 4.65:1 3:1 |
| border, error (darker) | 4.62:1 3:1 | 4.65:1 3:1 |
| border, hover and focus (lighter and darker) | 4.57:1 3:1 | 3.80:1 3:1 |
| read-only text | 18.09:1 AAA | 15.87:1 AAA |
| border, resize handle | 4.57:1 3:1 | 3.80:1 3:1 |
Text needs 4.5:1, icons and focus rings 3:1. Disabled states are exempt. Full contrast report