Textarea
- Component overview: Multi-line text input for comments, descriptions, and other long-form text entry.
- Size baseline: Min height 120px, max height 600px, horizontal padding 16px, vertical padding 8px, border radius 5px.
- Implementation note:
ui/textarearetains the multi-line input structure; the design layer owns the size, border, and state visuals. - Figma spec
Basic Usage
Result
Loading...
Live Editor
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, maxWidth: 400 }}> <Textarea placeholder="Enter content..." /> <Textarea placeholder="With initial value" defaultValue="Hello world, this is a textarea." /> </div>
States
4 visual states: Default / Focused / Error / Disabled.
Result
Loading...
Live Editor
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, maxWidth: 400 }}> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Default</span> <Textarea placeholder="Default state" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Error</span> <Textarea error placeholder="Error state" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Disabled (empty)</span> <Textarea disabled placeholder="Disabled" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Disabled (with value)</span> <Textarea disabled defaultValue="Read-only content" /> </div> </div>
| State | Border | Background | Note |
|---|---|---|---|
| Default | Separators/Emphasized#CCCCCC | transparent | — |
| Focused | Labels/Primary#000000 | transparent | Click to preview |
| Error | Status/Destructive#FF503F | transparent | error prop |
| Disabled | Separators/Emphasized#CCCCCC | Grays/Gray-1#EBEBEB | disabled prop |
Main Matrix
The current spec acceptance is based on State × Filled × Status. The doc site prioritizes the core combinations matching the current implementation.
Result
Loading...
Live Editor
<div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, minmax(0, 1fr))', gap: 16, maxWidth: 860 }}> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Normal / Empty / Default</span> <Textarea placeholder="Enter description..." /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Normal / Filled / Default</span> <Textarea defaultValue="Multi-line content already filled" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Focused / Empty / Default</span> <Textarea className="border-[var(--Labels-Primary)]" placeholder="Focused state" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Focused / Filled / Default</span> <Textarea className="border-[var(--Labels-Primary)]" defaultValue="Focused value" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Normal / Empty / Error</span> <Textarea error placeholder="Error state" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Normal / Filled / Error</span> <Textarea error defaultValue="Error value" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Disabled / Empty / Default</span> <Textarea disabled placeholder="Disabled empty" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>Disabled / Filled / Default</span> <Textarea disabled defaultValue="Disabled value" /> </div> </div>
Row Count Control
Use the rows prop to set the initial number of visible rows. Users can resize the textarea by dragging the resize handle (resize-y).
Result
Loading...
Live Editor
<div style={{ display: 'flex', flexDirection: 'column', gap: 16, maxWidth: 400 }}> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>rows=3</span> <Textarea rows={3} placeholder="3 rows tall" /> </div> <div style={{ display: 'flex', flexDirection: 'column', gap: 4 }}> <span style={{ fontSize: 12, color: '#999' }}>rows=8</span> <Textarea rows={8} placeholder="8 rows tall" /> </div> </div>
Size Spec
| Dimension | Value |
|---|---|
| Min height | 120px |
| Max height | 600px |
| Horizontal padding | 16px |
| Vertical padding | 8px |
| Border radius | 5px |
| Font | Body/Regular (14px, line-height 22) |
Props
| Prop | Type | Default | Description |
|---|---|---|---|
placeholder | string | - | Placeholder text |
value | string | - | Controlled value |
defaultValue | string | - | Initial value (uncontrolled) |
rows | number | - | Initial number of visible rows |
error | boolean | false | Error state — border uses Status/Destructive |
disabled | boolean | false | Disabled state |
onChange | ChangeEventHandler | - | Change callback |
aria-label | string | - | Accessibility label |