React Textarea
Textareas in React are controlled the same way text inputs are, but with one HTML quirk you need to unlearn: the value lives in the value attribute, not as inner text.
The HTML Quirk React Fixes
In plain HTML, a <textarea> stores its content as a child text node: <textarea>Hello</textarea>. React normalizes this so that a <textarea> behaves like every other form field — its content is set through a value attribute, exactly like <input value="...">. This consistency is what makes controlled textareas simple to reason about.
Building a Controlled Textarea
A controlled textarea reads its displayed text from a piece of state and writes back to that state on every onChange event. Because React re-renders with the new state, the textarea's value is always in sync with your component's data — there's no gap where the DOM and your JavaScript disagree about the current text.
Controlled Textarea with useState
import { useState } from 'react';
function FeedbackForm() {
const [message, setMessage] = useState('');
return (
<form>
<label htmlFor="feedback">Your feedback</label>
<textarea
id="feedback"
value={message}
onChange={(e) => setMessage(e.target.value)}
rows={5}
placeholder="Tell us what you think..."
/>
<p>{message.length} characters</p>
</form>
);
}
export default FeedbackForm;Sizing and Resizing
The rows and cols attributes set the initial visible size in character units, while CSS resize (none, vertical, horizontal, both) controls whether the user can drag to resize it. For a textarea that grows with content, you generally either set rows dynamically based on line count or reach for a small auto-resize library — React itself has no built-in autosize behavior.
- rows: number of visible text lines (default 2)
- cols: approximate visible width in characters (rarely used; prefer CSS width)
- maxLength: caps how many characters the user can type
- readOnly: still submits with the form but the user can't edit it
- disabled: excluded from form submission and cannot be focused
Validating and Limiting Input
Because onChange gives you the full new string on every keystroke, validation is just a conditional inside the handler. You can reject changes that would exceed a limit, strip disallowed characters, or simply mark the field invalid for a submit-time check.
Enforcing a Soft Character Limit with a Warning
import { useState } from 'react';
function BioField() {
const MAX = 160;
const [bio, setBio] = useState('');
const isOverLimit = bio.length > MAX;
return (
<div>
<textarea
value={bio}
onChange={(e) => setBio(e.target.value)}
rows={4}
/>
<p style={{ color: isOverLimit ? 'crimson' : 'gray' }}>
{bio.length}/{MAX}
</p>
</div>
);
}
export default BioField;Exercise: React Textarea
In plain HTML, a textarea's content sits between its opening and closing tags. How does React handle this?