Textarea
Multi-line text input for longer prose, with built-in size, state, and resize controls.
Description
Textarea is a multi-line text input rendered as a native <textarea>. It is a single-element component built around the same size and state model as the rest of the form primitives: xs, sm, md sizes, plus first-class loading, disabled, and invalid states surfaced through aria-invalid and a visual icon overlay.
Reach for it whenever a user needs to write more than one line: profile bios, message bodies, feedback, ticket descriptions, comments, prompts. Drop it inside Field to get a label, description, and helper text for free. Textarea reads size, loading, disabled, and invalid from Field via context, so a single <Field size="md"> cascades to its children without prop drilling.
Don't use Textarea for single-line input; Input is the right primitive there. For formatted or rich content (links, mentions, lists), use a dedicated rich-text editor instead. For structured key-value entries, compose multiple Field + Input rows rather than a single freeform textarea.
Installation
Usage
Examples
Sizes
Three sizes (xs, sm, md) adjust padding, radius, and type scale. sm is the default. When nested inside a Field, the textarea inherits size from the field; an explicit prop on the textarea always wins.
With Label
Wrap the textarea in Field and pair it with FieldLabel to get an accessible label. Use LabelRequired (or LabelOptional) for the required/optional indicator.
With Description
Add FieldDescription under the textarea for short, secondary copy explaining what the field is for. The description is rendered with reduced emphasis and linked to the textarea for assistive tech.
With Helper
Combine FieldHelper with LabelCount and maxLength to surface a live character counter alongside hint text. FieldHelper accepts an icon for inline status affordances.
Invalid
Set aria-invalid="true" on the textarea (or invalid on the parent Field, which cascades) to switch the textarea into the error state. The component renders a warning icon inside the textarea and re-tints the border, outline, text, and placeholder with the error tokens.
Loading
loading on the parent Field (or directly on the textarea) shows an animated spinner inside the textarea and makes it non-interactive. The textarea is also visually disabled and switches to the info-tinted border.
Disabled
disabled cascades from Field disabled and removes the textarea from the tab order. The component drops to the disabled tokens for background, text, and placeholder.
Resizable
resizable="x" | "y" | "both" re-enables the native resize handle and renders a custom corner glyph in its place. The native browser handle is hidden so the affordance matches the rest of the design system.
Accessibility
Textarea is a native <textarea>, so all of the platform's text-editing affordances apply. Keyboard shortcuts beyond the basics are handled by the browser.
ARIA notes:
- Uses native
<textarea>semantics; noroleis set. aria-invalidis forwarded to the underlying element and is automatically derived fromField'sinvalidprop, so wrapping the textarea in<Field invalid>is enough to expose the error to assistive tech.disabledremoves the textarea from the tab order;loadingalso marks it as disabled to block input while a save is in flight.- The status icons (loading spinner, invalid warning) are
aria-hiddenbecause they duplicate state already exposed througharia-invalid/disabled. Communicate the underlying reason throughFieldHelper,FieldDescription, or anaria-liveregion.
Styling
Tailwind override: pass className to merge Tailwind classes with the component's CVA classes (via cn()):
Data slots and attributes: the component sets these for CSS targeting:
data-slot="textarea"on the underlying<textarea>.data-slot="textarea-wrapper"on the wrapper element (only rendered whenresizableis set or a status icon is visible).data-slot="textarea-status-icon"on the loading / invalid icon overlay.data-size="<size>"on the textarea.data-loading(presence-only) on the textarea while loading.- Standard
aria-invalid="true"anddisabledattributes for error and disabled states; the component targets these directly rather than mirroring them asdata-*.
Target a specific state in CSS:
Related Components
- Input: single-line text input; same
Fieldcascade and state model. - Field: wraps form primitives to provide label, description, helper, and cascading
size/disabled/loading/invalid. - Label: primitives (
LabelRequired,LabelOptional,LabelCount,LabelBlock) used insideFieldLabel.
API Reference
Textarea
Multi-line text input that integrates with Field. Extends React.ComponentProps<"textarea"> with the native size attribute omitted so the design-system size axis can use it. Any other standard textarea attribute (name, value, defaultValue, placeholder, maxLength, onChange, aria-*, etc.) is accepted.