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
valuestring—Current value (controlled mode)
defaultValuestring""Initial value (uncontrolled mode)
onChange(value: string) => void—Called when value changes
onSubmit(value: string) => void—Called on submit key combo
submitKey"ctrl+enter" | "enter" | "meta+enter""ctrl+enter"Key to trigger submit
placeholderstring""Placeholder text when empty
isActiveboolean—Override 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"Active hardware and inactive visual cursor style
scrollMarginnumber1Context lines above/below cursor when scrolling
disabledboolean—Ignore input and dim text
maxLengthnumber—Maximum characters allowed
borderStylestring—Border style (e.g., "round", "single")
borderColorstring"$border"Border color when unfocused
focusBorderColorstring"$focusborder"Border color when focused
testIDstring—Test ID for focus system identification
wrap"soft" | "off""soft"Soft-wrap long logical lines (default) or keep them on a single visual row
colorstring—Foreground 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.