Textarea

Collects multi-line text; grows with its text from minRows to maxRows, then scrolls.

import { Textarea } from "@usefragments/ui";Source

Preview

<Field>
  <Field.Label>Description</Field.Label>
  <Textarea placeholder="What does this change do, and why?" />
  <Field.Description>Reviewers read this first.</Field.Description>
</Field>

Usage

Use when

  • Collecting multi-line text (comments, descriptions)
  • Free-form text input that may span multiple lines
  • Message composition fields

Avoid when

  • Single-line input (use Input)
  • Rich text editing (use Editor)
  • A chat composer with a toolbar (use Prompt)
  • Selecting from predefined options (use Select)

Implementation notes

  • Wrap in a Field for the label, description and error
  • Set minRows to the expected answer length and maxRows where the layout has a ceiling
  • Placeholder shows an example, not the label
  • maxLength shows the counter; past the limit it says so in words
  • Use resize="none" only when the layout truly cannot flex

Installation

pnpm add @usefragments/ui

Import styles once from @usefragments/ui/styles. See the installation guide for framework and theme setup.

Examples

With counter

maxLength shows a live count under the field.

<Field>
  <Field.Label>Bio</Field.Label>
  <Textarea
    maxLength={200}
    defaultValue="Design engineer on the checkout team. I look after our tokens and the standards every screen is checked against."
  />

Invalid

The danger edge with the reason under the field.

<Field invalid>
  <Field.Label>Reason for the exception</Field.Label>
  <Textarea placeholder="Why does this screen need a raw value?" />
  <Field.Error match>Add a reason so reviewers can approve the exception.</Field.Error>
</Field>

Grow to a ceiling

Starts at one row, grows to six, then scrolls.

<Field>
  <Field.Label>Notes</Field.Label>
  <Textarea
    minRows={1}
    maxRows={6}
    defaultValue={'Checkout: three raw colours\nCart: one spacing value\nHeader: icon button without a label'}

Sizes

Four steps on the control ladder.

<Stack gap="sm">
  <Textarea aria-label="Extra small" placeholder="Extra small" size="xs" minRows={1} />
  <Textarea aria-label="Small" placeholder="Small" size="sm" minRows={1} />
  <Textarea aria-label="Medium" placeholder="Medium" size="md" minRows={1} />
  <Textarea aria-label="Large" placeholder="Large" size="lg" minRows={1} />
</Stack>

Fixed height

resize="none" removes the drag handle.

<Field>
  <Field.Label>Release notes</Field.Label>
  <Textarea
    resize="none"
    defaultValue="Buttons, inputs and selects now share one control height ladder, so a row of mixed controls lines up without overrides."
  />

API reference

Component props
Prop
Type
Default
Description
defaultValuestring | undefinedNot setInitial value for uncontrolled use
invalidboolean | undefinedfalseThe danger edge and aria-invalid; say why in a Field.Error
maxLengthnumber | undefinedNot setThe most characters allowed. Setting it shows a counter under the field
maxRowsnumber | undefinedNot setRows the field grows to before it scrolls. Omit to grow without limit
minRowsnumber | undefined3Rows shown when empty; the field grows from here as text is added
onValueChange((value: string) => void) | undefinedNot setCalled with the new value on every change
resize"none" | "vertical" | undefinednoneverticalverticalWhether the person can drag the height. Width never resizes: it would break the column measure
sizeTextareaSize | undefinedxssmmdlg"md"Type size, inset and one-row height on the shared control ladder
valuestring | undefinedNot setControlled value
placeholderstring | undefinedNot setPlaceholder text
disabledboolean | undefinedfalseDims the field and blocks input
readOnlyboolean | undefinedfalseShows the text on a dashed edge without letting it change
onChangeChangeEventHandler<HTMLTextAreaElement> | undefinedNot setThe native change event
namestring | undefinedNot setForm field name
requiredboolean | undefinedNot setMarks the field required for form validation
classNamestring | undefinedNot setClass on the textarea
styleCSSProperties | undefinedNot set—

Accessibility

  • Field.Label names the textarea and Field.Description describes it
  • Field.Error is announced when it appears
  • Error text says what to fix, not just that it failed
  • FieldparentField supplies the label, description and error
  • InputalternativeUse Input for single-line text
  • PromptalternativeUse Prompt for a chat composer

Next steps