Skip to content
Cynosurev0.5.0
SearchStorybookGitHubnpmColour mode: System. Switch to Light

Components / Controls

TextArea

Multi-line text input. It starts at rows, grows with its content up to maxRows, then scrolls. For a single line, use TextField.

Grows then scrolls

When to useLink to "When to use"

  • Notes, comments, descriptions and other free text longer than a line.
  • A message or prompt with mentions (@name, #channel, a table name).
  • Input where a live character count helps (limits, annotations).

Use something else when:

UsageLink to "Usage"

tsx
Copy
import { TextArea } from "@arshad-shah/cynosure";

<TextArea label="Notes" name="notes" rows={3} maxRows={10} />
<TextArea label="Bio" maxLength={280} showCount value={bio} onChange={setBio} />
<TextArea label="Message" description="Plain text only" error={error} />

onChange receives the string value. Defaults are rows={3} and maxRows={12}.

Character counterLink to "Character counter"

showCount adds a live counter. With maxLength it reads "n / max", otherwise "n characters". Override the text with labels.count(count, max).

Counter and max length

ResizingLink to "Resizing"

A grip in the bottom corner lets pointer and touch users drag the height. The box keeps the chosen height and still grows with content, up to maxRows (or the chosen height, if that is taller). Pass resizable={false} to remove the grip. Disabled areas have none.

MentionsLink to "Mentions"

Give a trigger character and suggestions, and typing the trigger at the start of a word opens a list of suggestions for the text that follows it, up to the caret (no spaces). The arrow keys move through it, Enter or Tab (or a click or tap) puts the chosen value and a space in place of the trigger and the query, and Escape closes it for that mention. onMention(item) is called after the insertion, which is an ordinary edit: onChange hears it and Undo takes it back.

tsx
Copy
<TextArea
  label="Message"
  trigger="@"
  suggestions={[{ value: "@ada", label: "Ada Lovelace", description: "Engineering" }, "@alan"]}
  onMention={(item) => track(item.value)}
/>
<TextArea label="Ask" trigger="@" suggestions={(query) => searchTables(query)} />

suggestions is a list (strings, or items with a value, a label and a description), filtered by whether the value or a string label contains the query; or a function of the query that returns items or a promise of them. While a promise is pending the list says so (labels.loading) and is aria-busy; an answer for an older query is ignored, and a failed one closes the list. Nothing matching closes it too.

Mentions insert on enter

The list drops below the whole box, at least as wide as it, and moves above it when there is no room below (a chat input at the bottom of a window). It is the same list as Select, Combobox and TagInput use (OptionList).

OptionsLink to "Options"

  • variant: outline (default) or soft.
  • size: sm, md or lg.
  • labelHidden: hides the label visually while it still names the field. Prefer a visible label.
  • Native textarea attributes such as name, required, disabled, readOnly and maxLength pass through.

PropsLink to "Props"

Every prop of TextArea
PropWhat it doesTypeDefault
labelRequired
The field's label and accessible name.ReactNode
labelHidden
Visually hide the label (it still names the control). Prefer visible labels.boolean
description
Help text shown below the field.ReactNode
error
Error message shown below the field; it is announced and marks the field invalid.ReactNode
value
The text (controlled).string
defaultValue
Starting text when uncontrolled.string
onChange
Called with the new text on every edit.((value: string) => void)
resizable
Show a corner grip to drag the height (pointer and touch). Content growth still applies.boolean
rows
Minimum visible rows.number
maxRows
Auto-grow cap; content beyond scrolls.number
showCount
Shows a live character counter.boolean
size
Text size of the field and its label. Default "md".Size"md"
variant
outline or soft (tinted, borderless until focus). Default "outline"."soft" | "outline""outline"
trigger
Starts a mention: typed at the start of a word (such as "@"), it opens the suggestions list for the text that follows, up to the caret.string
suggestions
What the trigger offers: items filtered by the query (their value or string label contains it), or a function of the query returning items or a promise of them (stale answers are ignored).TextAreaSuggestions
onMention
Called with the suggestion chosen, after it is inserted.((item: TextAreaMention) => void)
labels
Replace the built-in English text: the character counter and the suggestion list's loading note.Partial<TextAreaLabels>
className
Added to the root element, for layout.string
style
Layout only.CSSProperties
layout
stack puts the label above the control and the description and error below it. split puts the label and description at the start and the control at the end of one row (a settings row); when the field is too narrow for both, the control moves under the text. Default "stack"."stack" | "split""stack"
width
Width of the control, so the controls of a column of fields line up: "sm", "md" and "lg" are the --cy-field-control-width-* tokens (never wider than the field), "full" is the whole field. Default: the control's own width (the whole field in the stacked layout for TextField and the other fields).FieldWidth

Generated from the type definitions in @arshad-shah/cynosure 0.5.0.

Behaviour and accessibilityLink to "Behaviour and accessibility"

  • Label, description and error are linked to the textarea through Field.
  • Counter: announced politely (aria-live="polite") and linked with aria-describedby.
  • Grip: a pointer and touch affordance only. It is aria-hidden, so keyboard users get content growth instead. It stays tucked in the corner on every device, and the text keeps a bottom margin so the last line never runs under it.
  • Forms: works with FormData, required, and reset restores the value, the count and the height.
  • Mentions: with trigger and suggestions the textarea has aria-autocomplete="list" and aria-haspopup="listbox"; while the list is open, aria-controls names it and aria-activedescendant the active option, so focus stays in the text. The list is named by the field's label, as Combobox's and TagInput's are. A textarea cannot take the combobox role or aria-expanded (ARIA in HTML), so the list being open is told by aria-controls and the active option. The keys the list uses while open (arrows, Enter, Tab, Escape) are not passed to your onKeyDown, so an "Enter sends" handler does not fire when Enter picks a suggestion; Shift+Enter still makes a new line. Nothing happens while an IME composes: the query is read when the composition ends, and its Enter belongs to the IME. Escape closes only the list, not a dialog or popover around the field.
Behaviour and accessibility, table 1
Key (list open)Result
Arrow Down / Arrow UpNext or previous suggestion (stops at the ends)
Enter / TabInserts the active suggestion and a space
EscapeCloses the list for this mention

ThemingLink to "Theming"

Tokens: --cy-text-area-{radius,padding-inline,padding-block,bg,border,soft-bg}.

ts
Copy
createTheme({ components: { textArea: { radius: "10px", paddingBlock: "10px" } } });

TextField · Select · SearchField

These examples run Cynosure 0.5.0 (commit 50ce30b), the version on npm.

Getting started
Theming
Icons
Accessibility
Code editors and highlighters
Using Cynosure without React
Build-tool adapters
Components
Accordion
AppShell
AspectRatio
Breadcrumbs
Calendar
Card
Container
Disclosure
Divider
DocumentViewport
Grid
Inline
PageHeader
PanZoomCanvas
ScrollArea
SideNav
SortableList
SplitPane
Stack
StatusBar
Tabs
TitleBar
Toolbar
Tree
VirtualList
ZoomControls
Announcer
Avatar
Badge
CodeBlock
DescriptionList
EmptyState
ErrorBoundary
Field
Heading
IconTile
Image
Kbd
List
LoadingDots
Notice
ProgressBar
Prose
Skeleton
Stat
Steps
Table
Text
Button
Checkbox
Checklist
ColorField
ColorSwatches
Combobox
CompareSlider
CopyButton
DateField
FileDrop
IconButton
KeyValueEditor
Link
NumberField
Pagination
PathField
RadioGroup
SearchField
SegmentedControl
Select
SelectionFrame
SignaturePad
Slider
Switch
TagInput
TextArea
TextField
ThemeToggle
TimeField
ButtonBase
ChoiceBase
DialogBase
FileInputBase
HiddenValue
Icon
InputBase
LinkBase
LiveRegion
TextAreaBase
ChatMessage
Choice
DataGrid
DeviceFrame
HighlightedText
HotkeyField
ListRow
OptionList
OverlayFrame
QRCode
RowActions
Section
SiteFooter
SiteHeader
SkipLink
SortButton
VisuallyHidden
CommandPalette
ContextMenu
Dialog
FloatingToolbar
HoverCard
Menu
Menubar
Popover
ProgressOverlay
Sheet
Toast
Tooltip
Changelog