Skip to content

TextArea

Multi-line text input with word wrapping, scrolling, selection, and full readline-style editing. Built on the same kill ring and word movement as TextInput.

Import

tsx
import { TextArea } from "silvery"

Usage

tsx
// Chat input — defaults give content-sized auto-grow (1..8 rows)
const [value, setValue] = useState("")

<TextArea
  value={value}
  onChange={setValue}
  onSubmit={send}
  placeholder="Type a message..."
/>

Sizing — field-sizing API

TextArea mirrors the CSS field-sizing property. The two modes are:

ModeVisible row countUse case
"content" (default)clamp(minRows, wrappedLines, maxRows)Chat / messaging input — auto-grow
"fixed"exactly rowsCode editor pane, designed footprint

In content mode the widget expands as the user types, capped at maxRows. Beyond that the buffer scrolls. Visual line counting respects soft wrap — a long single logical line that wraps to multiple visual rows counts toward minRows/maxRows.

tsx
// Default — chat-input (content mode, 1..8 rows)
<TextArea value={msg} onChange={setMsg} onSubmit={send} />

// Fixed 16-row code editor
<TextArea value={code} onChange={setCode} fieldSizing="fixed" rows={16} />

// Compose box — grows up to 12 rows then scrolls
<TextArea value={msg} onChange={setMsg} maxRows={12} />

Props

PropTypeDefaultDescription
valuestringCurrent value (controlled mode)
defaultValuestring""Initial value (uncontrolled mode)
onChange(value: string) => voidCalled when value changes
onSubmit(value: string) => voidCalled on submit key combo
submitKey"ctrl+enter" | "enter" | "meta+enter""ctrl+enter"Key to trigger submit
placeholderstring""Placeholder text when empty
isActivebooleanOverride focus system for input capture
fieldSizing"content" | "fixed""content"CSS field-sizing analog — auto-grow vs fixed
rowsnumber1Visible row count in "fixed" mode (mirrors HTML <textarea rows>)
minRowsnumber1Minimum visible rows in "content" mode
maxRowsnumber8Maximum visible rows in "content" mode (scrolls beyond)
cursorStyle"block" | "underline""block"Visual cursor style when unfocused
scrollMarginnumber1Context lines above/below cursor when scrolling
disabledbooleanIgnore input and dim text
maxLengthnumberMaximum characters allowed
borderStylestringBorder style (e.g., "round", "single")
borderColorstring"$border"Border color when unfocused
focusBorderColorstring"$focusborder"Border color when focused
testIDstringTest ID for focus system identification
wrap"soft" | "off""soft"Soft-wrap long logical lines (default) or keep them on a single visual row
colorstringForeground color for body text (e.g., "$fg-muted")
dimbooleanfalseShortcut for color="$fg-muted" — body text dims to muted

Migrating from height

The legacy height prop has been removed. Pick the new sizing prop based on the original intent:

Old usageNew usage
<TextArea height={N} /><TextArea fieldSizing="fixed" rows={N} />
Hand-rolled height={Math.min(N, lines.length)}<TextArea maxRows={N} /> (default content mode)
Chat input where height tracked content<TextArea /> (defaults are chat-input)

Ref Handle (TextAreaHandle)

Access via useRef<TextAreaHandle>():

MethodTypeDescription
clear()() => voidClear the input
getValue()() => stringGet current value
setValue(value)(value: string) => voidSet value programmatically
getSelection()() => TextAreaSelection | nullGet current selection range

Keyboard Shortcuts

KeyAction
Arrow keysMove cursor (clears selection)
Shift+ArrowExtend selection
Shift+Home/EndSelect to line boundaries
Ctrl+Shift+ArrowWord-wise selection
Ctrl+ASelect all text
Ctrl+EEnd of line
Ctrl+P / Ctrl+NUp / Down line (Emacs aliases)
Home / EndBeginning/end of line
Alt+B / Alt+FMove by word
Ctrl+W / Alt+BackspaceKill word backward
Alt+DKill word forward
Ctrl+KKill to end of line
Ctrl+UKill to beginning of line
Ctrl+YYank (paste from kill ring)
Alt+YCycle kill ring
Ctrl+TTranspose characters
PageUp / PageDownScroll by viewport height

Examples

Chat Input with Enter to Submit

tsx
<TextArea
  value={message}
  onChange={setMessage}
  onSubmit={sendMessage}
  submitKey="enter"
  placeholder="Type a message..."
/>

With submitKey="enter", pressing Enter submits. Use Shift+Enter or the default "ctrl+enter" for newlines. Defaults to content-mode auto-grow (minRows=1, maxRows=8).

Bordered Editor

tsx
<TextArea
  value={content}
  onChange={setContent}
  fieldSizing="fixed"
  rows={15}
  borderStyle="round"
  placeholder="Write your note..."
/>

Disabled State

tsx
<TextArea value={readOnlyContent} fieldSizing="fixed" rows={10} disabled />

When disabled, text is dimmed and all input is ignored.