Skip to content
Components

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

Shown on the project card.

Props

  • size
  • resize
  • rows
  • disabled
  • label
  • placeholder
  • error
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.

  • Shown on the project card.

    sm

  • Shown on the project card.

    mddefault

  • Shown on the project card.

    lg

  • Shown on the project card.

    xl

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.

  • Shown on the project card.

    none

  • Shown on the project card.

    verticaldefault

  • Shown on the project card.

    both

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

Shown on the project card.

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.

Tell us in a sentence or two.

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

NameTypeValuesDefaultDescription
sizeenumsm | md | lg | xlmdPadding and minimum height, matching the Input of the same size. Use the size of the other fields in the form.
resizeenumnone | vertical | bothverticalWhich way the user can drag the corner. vertical keeps the width of the form; none for a fixed box, such as a chat composer.
rowsnumber-3Visible lines before the text scrolls. Pick it for the text you expect: 3 for a comment, 6 or more for a description.
disabledboolean-falseCan't be focused or edited. Prefer readOnly for a value the user should still read and copy.
readOnlyboolean-falseCan be focused, scrolled and copied, but not edited. Same look as an editable textarea.

Anatomy

PartDescription
rootThe 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.
placeholderHint text shown when the value is empty. Colored with text-secondary, so it reaches 4.5:1 on the sunken fill.

Accessibility

Role: textbox

KeysAction
TabMoves focus in and out of the textarea; inside it, Tab is not captured.
EnterStarts 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.json

This 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").