Components
Text Area
Multiline inputs for text
TextAreaV2 is built on React Aria and styled with Thumbprint v2 semantic tokens. Like v1 it is a controlled component: the visible text always matches the value prop, and onChange hands back the new value so you can store it in state.
The field also renders its own label and helper text. Prefer the label, description, and errorMessage props over composing Label and FormNote siblings: React Aria generates the ids and wires up the label association and aria-describedby, so the field is accessible with no ids to keep unique and no way for the error styling and the error text to fall out of sync.
Label
The label prop renders the label above the textarea and associates the two for assistive technologies. Every field needs a label; when the design has no room for a visible one, pass accessibilityLabel instead.
function TextAreaExample() { const [value, setValue] = React.useState(''); return ( <TextAreaV2 label="Project details" value={value} placeholder="Tell us about your project" onChange={setValue} /> ); }
Description
The description prop renders helper text below the textarea and points the textarea’s aria-describedby at it, so screen readers announce it along with the label.
function TextAreaExample() { const [value, setValue] = React.useState(''); return ( <TextAreaV2 label="Project details" description="The more you share, the more accurate your quotes will be." value={value} placeholder="Tell us about your project" onChange={setValue} /> ); }
Error message
The errorMessage prop puts the textarea in the error state — there is no separate hasError to remember — and renders the message below it. It replaces the description while the error is showing, so you can pass both and let the field swap them.
The error state is visual only, as it was in v1: it sets aria-invalid but leaves native validity alone, so a <form> holding an errored textarea still submits and your own validation stays in charge. isRequired is unaffected — it still applies the native required attribute, which the browser does enforce.
function TextAreaExample() { const [value, setValue] = React.useState('Help'); const errorMessage = value.length < 20 ? 'Please describe your project in at least 20 characters.' : undefined; return ( <TextAreaV2 label="Project details" description="The more you share, the more accurate your quotes will be." errorMessage={errorMessage} value={value} onChange={setValue} /> ); }
Error styling without a message
hasError turns the label, text, and border red without rendering a note. Use it only when the message lives elsewhere — such as a summary at the top of the form — since an error state with no explanation leaves users stuck.
function TextAreaExample() { const [value, setValue] = React.useState('Help'); return <TextAreaV2 label="Project details" hasError value={value} onChange={setValue} />; }
Disabled textarea
The isDisabled prop disables the textarea visually and functionally, and dims the built-in label along with it.
function TextAreaExample() { const [value, setValue] = React.useState('Repaint two bedrooms and the upstairs hallway.'); return <TextAreaV2 label="Project details" isDisabled value={value} onChange={setValue} />; }
Read-only textarea
The isReadOnly prop adds the readonly attribute, letting users focus and select the text without editing it. There is no separate read-only look, and read-only textareas are still submitted with the form, so an errorMessage on one still shows. A disabled textarea is the opposite: it keeps the disabled treatment and its error is not shown, since the browser skips disabled fields when submitting.
function TextAreaExample() { const [value, setValue] = React.useState('Repaint two bedrooms and the upstairs hallway.'); return <TextAreaV2 label="Project details" isReadOnly value={value} onChange={setValue} />; }
Limiting length
The maxLength prop caps the number of characters the browser accepts; onChange stops firing once the limit is reached. Say what the limit is in the description so it isn’t a surprise.
function TextAreaExample() { const [value, setValue] = React.useState(''); return ( <TextAreaV2 label="Project details" description="Up to 60 characters." maxLength={60} value={value} placeholder="Tell us about your project" onChange={setValue} /> ); }
Using an external Label and FormNote
For call sites that have not moved to the props yet, a sibling Label and FormNote still work: the id prop lands on the <textarea> element, so Label’s for associates the two natively. You are then responsible for keeping the ids unique and, in the error state, for keeping the hasError flags on all three components in sync — which is why the label, description, and errorMessage props are the better choice for new code.
In development, React Aria logs a console warning for this pattern because it can’t detect the external for/id association. The association is real and accessible, so the warning can be ignored; passing label or accessibilityLabel silences it.
function TextAreaExample() { const [value, setValue] = React.useState(''); return ( <div> <Label for="example-text-area-v2">Project details</Label> <TextAreaV2 id="example-text-area-v2" value={value} placeholder="Tell us about your project" onChange={setValue} /> <div className="mt1"> <FormNote>The more you share, the more accurate your quotes will be.</FormNote> </div> </div> ); }
Props
TextAreaV2
valuerequiredThe current value of the textarea.
TypestringonChangerequiredThe function that is called when the textarea value changes.
It receives two arguments:
onChange(newValue, event).The consumer of this component should use that data to update the
valueprop passed in to this component.Type(newValue: string, event: React.ChangeEvent<HTMLTextAreaElement>) => voididAdds a HTML
idattribute to the textarea. This is used for linking the HTML with an external Label, matching the v1TextAreapattern. Note: when neitherlabelnoraccessibilityLabelis provided, react-aria logs a development-only console warning it cannot detect the nativefor/idassociation. The association is real and accessible; the warning can be ignored (or avoided by using thelabelprop).TypestringlabelText that appears above the textarea, replacing the need for a separate
Labelcomponent. The label is automatically associated with the textarea for assistive technologies.Prefer this over
accessibilityLabel: a visible label serves everyone, not only screen reader users, and clicking it focuses the textarea. UseaccessibilityLabelonly when the design leaves no room for visible text.TypestringdescriptionText that appears below the textarea, replacing the need for a separate
FormNotecomponent. When the textarea is in an error state with anerrorMessage, the error message is shown in its place.TypeReact.ReactNodeerrorMessageError text that appears below the textarea, replacing the need for a separate
FormNotecomponent. Providing anerrorMessageputs the textarea in the error state — no separatehasErrorneeded.TypeReact.ReactNodeisDisabledVisually and functionally disable the textarea.
TypebooleanDefaultfalseisReadOnlyAdds
readonlyHTML attribute, allowing users to select (but not modify) the textarea.TypebooleanDefaultfalseisRequiredAdds the
requiredHTML attribute to the textarea.TypebooleanDefaultfalsehasErrorMakes the textarea border and text color red.
TypebooleanDefaultfalseplaceholderText that appears within the textarea when there is no
value.TypestringnameAdds
nameHTML attribute to element, indicating the property name associated with the selected value.TypestringmaxLengthThe maximum number of characters that a user can enter.
onChangewill not fire if a user enters a character that exceedsmaxLength.TypenumberonFocusFires when the textarea receives focus.
Type(event: React.FocusEvent<HTMLTextAreaElement>) => voidonBlurFires when the textarea loses focus.
Type(event: React.FocusEvent<HTMLTextAreaElement>) => voidonKeyDownFires when a key is pressed down with the textarea focused.
Type(event: React.KeyboardEvent<HTMLTextAreaElement>) => voidonKeyUpFires when a key press is released with the textarea focused.
Type(event: React.KeyboardEvent<HTMLTextAreaElement>) => voiddataTestIdA selector hook into the React component for use in automated testing environments. It is applied internally to the
<textarea />element.TypestringaccessibilityLabelAccessible label for the textarea, applied as the
aria-labelattribute. Only needed if there is nolabelprop or associated label element. If you see react-aria's development-only warning asking foraria-labeloraria-labelledby, this prop — orlabel— is the fix.Typestring