Textarea
Multi-line free text — comments, messages, descriptions, prompts. Reach for it when input can run past one line or wrap; use Input for single-line values (name, email, search) and Combobox/Select when the value comes from a known set. Flat surface — white fill, 10% border, rounded (6px), no inner shadow — matching Input's fill, hover overlay, and focus ring, with an 80px min-height and resize-y. Use invalid for failed validation, readOnly for non-editable-but-readable content, and disabled when the field is inactive.
Basic
<Textarea placeholder="Type your message here…" />With an action bar
// Pattern: Textarea + an action bar below. The whole wrapper — textarea and
// action bar — shares one border + hover + focus + invalid state. The inner
// Textarea strips its own chrome so only the wrapper renders them.
//
// LEFT: context (model picker, tool toggles, scope)
// RIGHT: actions (upload, mic, and the primary Send button)
<div
className={cn(
"rounded border border-input bg-input-fill",
"transition-[box-shadow,border-color,background-image] duration-150 ease-out",
"hover:[background-image:linear-gradient(var(--surface-hover-overlay),var(--surface-hover-overlay))]",
"focus-within:shadow-ring-primary-input focus-within:border-focus",
"has-[[aria-invalid=true]]:border-[var(--border-destructive-50)]",
"has-[[aria-invalid=true]]:focus-within:shadow-ring-destructive-input"
)}
>
<Textarea
placeholder="Type your message here…"
className="!border-0 !bg-transparent resize-none
hover:!bg-none focus-visible:!border-transparent"
/>
{/* All controls share h-8 so the bar reads as a single row. */}
<div className="flex items-center justify-between gap-2 px-2 pb-2 ">
<div className="flex items-center gap-1">
<Button variant="outline" className="text-sm" iconTrailing={<Chevron />}>Claude Opus 4.6</Button>
<Button variant="ghost" className="text-sm" iconLeading={<Plus />}>Add</Button>
</div>
<div className="flex items-center gap-1">
<IconButton variant="ghost" aria-label="Attach file"><Paperclip /></IconButton>
<IconButton variant="ghost" aria-label="Record"><Mic /></IconButton>
<IconButton variant="primary" aria-label="Send"><ArrowUp /></IconButton>
</div>
</div>
</div>Rule: the action bar is two button groups — left for context (model picker, mode, scope) and right for actions (upload, mic, then the primary Send button). The Send button is the only Primary in the group and sits at the far right.
States
<>
<Textarea placeholder="Default" />
<Textarea disabled defaultValue="cannot edit" />
<Textarea readOnly defaultValue="read only" />
<Textarea invalid defaultValue="too short" />
</>Props
| Prop | Type | Default |
|---|---|---|
| invalid | boolean | false |
| disabled | boolean | false |
| readOnly | boolean | false |
| …rest | TextareaHTMLAttributes | — |
Source
packages/react/src/components/textarea.tsx · Figma node 2819:31165