Skip to main content

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/textarea retains 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>
StateBorderBackgroundNote
DefaultSeparators/Emphasized#CCCCCCtransparent
FocusedLabels/Primary#000000transparentClick to preview
ErrorStatus/Destructive#FF503Ftransparenterror prop
DisabledSeparators/Emphasized#CCCCCCGrays/Gray-1#EBEBEBdisabled 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

DimensionValue
Min height120px
Max height600px
Horizontal padding16px
Vertical padding8px
Border radius5px
FontBody/Regular (14px, line-height 22)

Props

PropTypeDefaultDescription
placeholderstring-Placeholder text
valuestring-Controlled value
defaultValuestring-Initial value (uncontrolled)
rowsnumber-Initial number of visible rows
errorbooleanfalseError state — border uses Status/Destructive
disabledbooleanfalseDisabled state
onChangeChangeEventHandler-Change callback
aria-labelstring-Accessibility label