Textarea
Text field over several lines, for a description, a comment or a message. Input's field box: the same sunken fill, control border, radius, 14px text (16px on touch) and states. One line plus its padding matches the Input height of the same size.
Preview
import { Field, FieldControl, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>Usage
When to use
- Text over several lines: a description, a comment, a message to the team.
- A value the user pastes in, such as a list of addresses, one per line.
When not to use
- A single line, such as a name, an email or a search. Use Input.
- Picking from known options. Use Select.
Variants
size
Padding and minimum height, matching the Input of the same size. Use the size of the other fields in the form.
import { Field, FieldControl, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea size="sm" placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea size="lg" placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea size="xl" placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>resize
Which way the user can drag the corner. vertical keeps the width of the form; none for a fixed box, such as a chat composer.
import { Field, FieldControl, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea resize="none" placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea resize="both" placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>Examples
Default
import { Field, FieldControl, FieldDescription, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
<Field className="w-full max-w-md">
<FieldLabel>Description</FieldLabel>
<FieldControl>
<Textarea placeholder="What is this project about?" />
</FieldControl>
<FieldDescription>Shown on the project card.</FieldDescription>
</Field>With an error
The error text marks the textarea invalid and is read after its name.
import { Field, FieldControl, FieldError, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
<Field className="w-full max-w-md" required>
<FieldLabel>Reason for leaving</FieldLabel>
<FieldControl>
<Textarea rows={4} />
</FieldControl>
<FieldError>Tell us in a sentence or two.</FieldError>
</Field>Read only
Focusable and copyable, but not editable.
import { Field, FieldControl, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
<Field className="w-full max-w-md">
<FieldLabel>Webhook payload</FieldLabel>
<FieldControl>
<Textarea readOnly rows={4} defaultValue="event: project.created" />
</FieldControl>
</Field>Disabled
import { Field, FieldControl, FieldLabel } from "@/components/ui/field"
import { Textarea } from "@/components/ui/textarea"
<Field className="w-full max-w-md" disabled>
<FieldLabel>Notes</FieldLabel>
<FieldControl>
<Textarea defaultValue="Archived projects can't be edited." />
</FieldControl>
</Field>Do and don't
Do
- Put it in a Field, so it has a visible label and its description and error are linked.
- Set rows for the text you expect, so the box shows how much to write.
- Use the same size as the other fields in the form.
Don't
- Don't use it for a single line, such as a name or an email; use Input.
- Don't use a placeholder instead of a label.
- Don't make Enter submit the form; people expect a new line.
Props
| Name | Type | Values | Default | Description |
|---|---|---|---|---|
| size | enum | sm | md | lg | xl | md | Padding and minimum height, matching the Input of the same size. Use the size of the other fields in the form. |
| resize | enum | none | vertical | both | vertical | Which way the user can drag the corner. vertical keeps the width of the form; none for a fixed box, such as a chat composer. |
| rows | number | - | 3 | Visible lines before the text scrolls. Pick it for the text you expect: 3 for a comment, 6 or more for a description. |
| disabled | boolean | - | false | Can't be focused or edited. Prefer readOnly for a value the user should still read and copy. |
| readOnly | boolean | - | false | Can be focused, scrolled and copied, but not edited. Same look as an editable textarea. |
Anatomy
| Part | Description |
|---|---|
| root | The textarea element: sunken fill, control border, radius-element, 14px text at body leading (16px on touch, so iOS doesn't zoom). Never shorter than size-element-* of its size. |
| placeholder | Hint text shown when the value is empty. Colored with text-secondary, so it reaches 4.5:1 on the sunken fill. |
Accessibility
Role: textbox
| Keys | Action |
|---|---|
| Tab | Moves focus in and out of the textarea; inside it, Tab is not captured. |
| Enter | Starts a new line. It never submits the form. |
- Name it with a visible label. Inside a Field, FieldLabel points at it and FieldControl links its description and error.
- A placeholder is a hint, not a label: it disappears as soon as the user types.
- aria-invalid shows the danger border; pair it with error text, since the border alone relies on color. A FieldError does both.
- A textarea is a replaced element, so it has no ::before hit area. It is never shorter than a control of its size.
- Disabled text can still scroll, so nothing in a long value is lost from view.
Install
npx shadcn add https://werewolf-ui.vercel.app/r/textarea.jsonThis also adds styles/werewolf.css, the tokens every component uses, and any other component it needs. Import that file once in your root CSS, after @import "tailwindcss", with a path relative to that CSS file (from app/globals.css it is @import "../styles/werewolf.css").