How to Manage the textarea Value in React: Controlled vs Uncontrolled Patterns
React provides two distinct patterns for managing textarea content: controlled components using the value prop with an onChange handler, and uncontrolled components using defaultValue where the DOM manages subsequent edits.
React treats the <textarea> element as a standard form input within its reconciliation layer, offering explicit mechanisms to manage its content through specific props. Whether you need real-time validation or simple form submission handling, understanding the distinction between controlled and uncontrolled patterns—as implemented in the facebook/react repository—is essential for predictable form behavior.
Controlled textarea Components
A controlled textarea derives its content from React state, making JavaScript the single source of truth for the displayed text.
The value Prop and State Synchronization
In a controlled implementation, the value prop receives state that drives the textarea's display. React writes this value directly to the underlying DOM node on every render through the internal ReactDOMTextarea module located at [packages/react-dom/src/client/ReactDOMTextarea.js](https://github.com/facebook/react/blob/main/packages/react-dom/src/client/ReactDOMTextarea.js).
function ControlledExample() {
const [text, setText] = React.useState('Hello, world!');
return (
<textarea
value={text}
onChange={e => setText(e.target.value)}
/>
);
}
The onChange Handler Requirement
Every user edit triggers the onChange handler, which must update the supplying state. Without this callback, React logs a warning and freezes the textarea in read-only mode because the rendered value remains unchanged while the DOM attempts to accept new input.
Warning Behavior on Missing Handlers
If you supply a value without an onChange (or with a no-op handler), React issues a console warning stating that the textarea is a controlled component, and the field becomes unresponsive to user input.
Uncontrolled textarea Components
An uncontrolled textarea lets the browser manage the text content, with React only setting the initial value.
Using defaultValue for Initial Content
Use the defaultValue prop to set the starting text. After the first render, the DOM owns the value and React does not interfere with subsequent edits.
function UncontrolledExample() {
const textareaRef = React.useRef(null);
const handleSubmit = () => {
alert(`Current content: ${textareaRef.current?.value}`);
};
return (
<>
<textarea defaultValue="Start typing…" ref={textareaRef} />
<button onClick={handleSubmit}>Submit</button>
</>
);
};
Updating defaultValue After Mount
When the component re-renders with a different defaultValue prop, React updates the DOM to match the new initial value. This behavior is verified in [packages/react-dom/src/__tests__/ReactDOMTextarea-test.js](https://github.com/facebook/react/blob/main/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js) around line 344 in the test "should take updates to defaultValue for uncontrolled textarea".
Children Prop Error
Providing children inside <textarea> (e.g., <textarea>some text</textarea>) triggers a runtime error. React explicitly warns against this pattern and directs developers to use value or defaultValue instead, as documented in the same test file around lines 448-452.
Edge Cases and Performance Patterns
Read-Only Controlled Display
For static content that should appear editable but remain immutable, use a controlled pattern with the HTML readOnly attribute:
<textarea value="Fixed text" readOnly />
This maintains the controlled architecture while signaling to the browser that the field is not editable.
Programmatic Value Changes
To change a textarea's content programmatically, update the state that drives the value prop in controlled mode, or remount the component with a new key and defaultValue in uncontrolled mode. Direct DOM mutation through textarea.value is discouraged because React's reconciler will override manual changes during the next render cycle unless you use the proper prop interface.
Performance Optimization for Large Text
For performance-critical applications handling large text blocks, prefer the uncontrolled pattern with defaultValue. This avoids re-rendering the component on every keystroke. Access the current value via a ref when needed rather than storing the entire text in React state.
React Internals and Event Handling
The ReactDOMTextarea module normalizes defaultValue and value handling while registering change and input events to keep React's synthetic event system synchronized.
In [packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js](https://github.com/facebook/react/blob/main/packages/react-dom/src/events/plugins/__tests__/ChangeEventPlugin-test.js) (lines 130-160), you can observe how React avoids dispatching change events when the value hasn't actually changed, preventing unnecessary state updates.
The [packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js](https://github.com/facebook/react/blob/main/packages/react-dom/src/events/plugins/__tests__/SimpleEventPlugin-test.js) suite (around line 142) confirms that textarea elements correctly participate in React's generic event plugin infrastructure, ensuring consistent cross-browser behavior.
Summary
- Choose controlled (
value+onChange) when you need React as the single source of truth for form validation, instant UI feedback, or state synchronization. - Choose uncontrolled (
defaultValue+ref) when you want the browser to manage the text and only need the final value, particularly for large editors or lazy-save scenarios. - Never use children inside textarea tags; always use
valueordefaultValueto set initial content. - Provide
onChangewhenever you supply avalueprop, or React will treat the textarea as read-only and issue a console warning.
Frequently Asked Questions
What happens if I provide a value prop without an onChange handler?
React will treat the textarea as a read-only controlled component and log a warning to the console. The UI will appear frozen because React continuously resets the DOM value to match the unchanged prop on every render, preventing user edits from persisting.
How do I update an uncontrolled textarea's value programmatically?
Change the defaultValue prop and force a remount by supplying a different key attribute, or use a ref to access the DOM node directly. However, if you need frequent programmatic updates, consider converting to a controlled component instead.
Why does React warn against putting text between textarea tags?
React enforces that textarea content must be set via the value or defaultValue props, not children. This design prevents ambiguous behaviors between HTML's default content and React's prop-driven updates. The warning appears in [ReactDOMTextarea-test.js](https://github.com/facebook/react/blob/main/packages/react-dom/src/__tests__/ReactDOMTextarea-test.js) around lines 448-452 if children are detected.
Which approach performs better for large text inputs?
The uncontrolled pattern using defaultValue performs better for large text because it avoids re-rendering the entire component tree on every keystroke. Use a ref to read the current value only when necessary, such as during form submission, rather than storing the full text in React state.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s https://instagit.com/install.md