Textarea
Multiline text control with character limits and optional auto-growing rows
The Textarea component is a multiline text-entry control for notes, descriptions, comments, and other longer values. It follows the same field conventions as Input—labels, descriptions, errors, variants, disabled state, clear actions, controlled values, and character counters—but intentionally has one visual size instead of size variants.
Installation
import { Textarea } from '@mosmox/ui';Basic usage
<Textarea label="Notes" placeholder="Write your notes" />The component renders a native <textarea> and forwards native textarea attributes and events.
Value management
Use defaultValue for an uncontrolled textarea:
<Textarea label="Summary" defaultValue="Initial summary" />Use value and onChange when the parent owns the value:
const [description, setDescription] = useState('');
<Textarea
label="Description"
value={description}
onChange={(event) => setDescription(event.target.value)}
placeholder="Describe the project"
/>The component also forwards native properties such as name, id, required, placeholder, autoComplete, inputMode, form, and tabIndex.
Labels, descriptions, and errors
label creates an associated label. description provides supporting guidance, while error displays validation feedback and activates the error border and focus treatment.
<Textarea
label="Release notes"
description="Summarize the important changes."
error="Release notes are required."
required
/>The component connects description and error IDs through aria-describedby and derives aria-invalid from the presence of error unless an explicit value is provided.
Rows and auto-growing behavior
minRows defines the initial number of visible text rows. It is also used as the native rows value. The textarea has one standard visual size; row count controls its vertical space.
<Textarea label="Comment" minRows={4} placeholder="Write a comment" />Set autoResize to make the textarea grow as the user enters line breaks. maxRows caps the automatic height. Once the maximum is reached, the control scrolls internally instead of growing without limit.
<Textarea
label="Expandable notes"
autoResize
minRows={2}
maxRows={6}
placeholder="Press Enter to add another line"
/>maxRows is normalized so it cannot be smaller than minRows. When autoResize is false, the user can resize the textarea vertically using the native resize affordance.
Manual resize control
Use resize to control whether the user can manually change the textarea dimensions:
<Textarea label="Fixed" resize="none" />
<Textarea label="Vertical only" resize="vertical" />
<Textarea label="Both directions" resize="both" />nonedisables manual resizing.verticalallows height changes only and is the default.bothallows width and height changes.
When autoResize is enabled, automatic sizing takes precedence and manual resizing is disabled.
Character limits
Pass maxLength to enforce a native maximum character count. When present, the component displays current / maximum below the field on the right.
<Textarea
label="Short description"
maxLength={160}
placeholder="Up to 160 characters"
/>The counter works with both controlled and uncontrolled values, including an initial defaultValue. The browser prevents additional input after the limit is reached.
Variants
variant supports the same two surface treatments as Input:
<Textarea label="Outline" variant="outline" />
<Textarea label="Filled" variant="filled" />outlineis the default bordered surface.filleduses the shared control-filled background token and removes the visible border.
Clear action
Set clearable to show a clear button when the textarea has editable content. onClear is called when the button is activated.
const [notes, setNotes] = useState('Draft notes');
<Textarea
label="Notes"
value={notes}
onChange={(event) => setNotes(event.target.value)}
clearable
onClear={() => setNotes('')}
/>The clear button is hidden for empty, disabled, or read-only values. For controlled usage, the parent must clear the value in onClear.
Disabled and read-only values
Use disabled when the textarea is unavailable. Use native readOnly when the value should remain selectable but not editable.
<Textarea label="Read-only notes" value="Approved content" readOnly />
<Textarea label="Unavailable notes" value="Locked content" disabled />Full width
Use fullWidth to make the field fill its parent container.
<Textarea fullWidth label="Full-width description" minRows={4} />Accessibility
labelis associated with the native textarea throughhtmlForandid;descriptionanderrorare referenced througharia-describedby;errorsetsaria-invalidunless explicitly overridden;required,readOnly, anddisabledpreserve native textarea semantics;- the character counter uses a polite live region;
- native keyboard, selection, focus, form, and browser validation behavior is preserved.
Use a visible label instead of relying only on placeholder text.
Styling model
The component uses shared theme tokens for colors, typography, radius, and control surfaces. Textarea-specific layout, auto-resize behavior, and state rules remain in Textarea.css. The component does not expose the Input size variants; its height is controlled by minRows, maxRows, and autoResize.
API Reference
Textarea-specific properties
| Property | Type | Default | Description |
|---|---|---|---|
label | string | — | Associated field label. |
description | string | — | Supporting text below the label. |
error | string | — | Validation message and invalid visual state. |
variant | TextareaVariant | outline | outline or filled. |
minRows | number | 3 | Initial and minimum visible row count. |
maxRows | number | 8 | Maximum automatic row count. Normalized to at least minRows. |
autoResize | boolean | false | Grows with line breaks up to maxRows. |
resize | TextareaResize | vertical | Manual resize mode: none, vertical, or both. |
clearable | boolean | false | Shows a clear action for editable, non-empty values. |
onClear | () => void | — | Called when the clear action is activated. |
fullWidth | boolean | false | Expands the field to its container width. |
className | string | — | Additional class name for the field wrapper. |
Native textarea properties
Textarea accepts TextareaHTMLAttributes<HTMLTextAreaElement> except for native rows and size. Use minRows instead of rows; the component controls the native rows value.
| Property | Type | Default | Description |
|---|---|---|---|
value | `string | number | readonly string[]` |
defaultValue | `string | number | readonly string[]` |
onChange | ChangeEventHandler<HTMLTextAreaElement> | — | Called when the value changes. |
maxLength | number | — | Maximum characters and counter limit. |
readOnly | boolean | false | Prevents editing while preserving selection and focus. |
disabled | boolean | false | Disables interaction. |
required | boolean | false | Enables native required-field validation. |
placeholder | string | — | Placeholder shown when empty. |
name | string | — | Form submission name. |
id | string | generated | Textarea ID used by the label and messages. |
aria-label | string | — | Accessible name when no visible label is used. |
aria-describedby | string | generated | Additional description IDs; component message IDs are appended. |
aria-invalid | `boolean | 'true' | 'false'` |
All other supported native textarea properties and event handlers are forwarded to the underlying <textarea> element.