Controlled and uncontrolled React forms differ in one thing: who owns each input's value. A controlled input stores its value in React state, while an uncontrolled input leaves the value in the browser DOM and reads it only when needed. The table below shows how the two split responsibilities.
The difference in one table
| Aspect | Controlled | Uncontrolled |
|---|---|---|
| Source of truth | React state | The DOM node |
| Value prop | value | defaultValue |
| Change handling | onChange updates state | Optional, read on demand |
| Reading the result | From state | FormData or a ref |
| Re-renders on typing | Yes, the field re-renders | No extra render |
The table is the whole mental model. With a controlled input, React knows the current value on every render. With an uncontrolled input, React only touches the DOM when you tell it to read or reset the value.
Build the controlled version
A controlled field pairs a value prop with an onChange handler. Every keystroke updates state, and the field re-renders to match.
import { useState } from "react";
export default function ControlledEmail() {
const [email, setEmail] = useState("");
return (
<label>
Email
<input value={email} onChange={(e) => setEmail(e.target.value)} />
</label>
);
}Typing updates state immediately, so the email variable always holds the latest text. That makes controlled inputs the easy choice when another part of the UI needs the value live, such as a character counter, a disabled submit button that waits for a complete address, or a search box that filters a list as you type.
Build the uncontrolled version
An uncontrolled field sets a starting value with defaultValue and leaves later edits to the DOM. You read the result on submit with FormData or a ref.
import { useRef } from "react";
export default function UncontrolledEmail() {
const inputRef = useRef(null);
function handleSubmit(e) {
e.preventDefault();
alert(`Email is ${inputRef.current.value}`);
}
// the return below continues this same componentThe ref points at the DOM node, and the handler reads its current value once when the form is submitted.
return (
<form onSubmit={handleSubmit}>
<label htmlFor="email">Email</label>
<input id="email" defaultValue="" ref={inputRef} />
<button type="submit">Submit</button>
</form>
);
}Nothing re-renders while the user types, because React is not watching each keystroke. The handler reads the value once from the ref when the form is submitted.
React Hook Form is built on this same idea, which is why it re-renders far less than controlled forms. For a full walkthrough, see the React Hook Form tutorial.
Why the re-render difference matters
In a large form, a controlled input re-renders the component on every keystroke, and a slow keystroke inside a long list can drop frames. An uncontrolled input does not re-render while typing, which keeps big forms responsive. This is the main difference you will actually feel, and it is why React Hook Form chose the uncontrolled model.
Small forms rarely notice, so the decision matters most as the form grows. Choose the model that matches the feedback your UI needs, then let the form's size push you toward uncontrolled when typing starts to feel slow.
Which should you use?
Choose controlled inputs when the value drives other UI or needs live validation. Choose uncontrolled inputs for simple forms where you only care about the final values, or when you want to avoid per-keystroke renders.
- Use controlled when the value must update other state or UI as you type.
- Use uncontrolled for simple search, login, and submit-and-read flows.
- Mixing them is fine when each field has a clear owner.
A common false equivalence is treating defaultValue like a value prop. defaultValue only sets the initial render; changing it later does nothing.
If you need React to keep driving the field, use value plus onChange, which is the controlled pattern. React 19 form actions also reset uncontrolled fields after a successful submit, which is another reason the two models behave differently.
Client-side checks work in both models. See React form validation without a library to validate either style, or how to build forms in React for the full setup path.
Rune AI
Key Insights
- Controlled inputs store the value in state and re-render on each change.
- Uncontrolled inputs read the value later with FormData or a ref.
- value drives a controlled field, while defaultValue only seeds the first render.
- Use controlled for live UI, uncontrolled for simple submit flows.
- One field should have one clear owner.
Frequently Asked Questions
Which is better, controlled or uncontrolled?
Does defaultValue update when I change it later?
Can I mix controlled and uncontrolled fields in one form?
Conclusion
Controlled inputs put React in charge of the value, and uncontrolled inputs leave it in the DOM. Pick controlled for live feedback and uncontrolled for simple submit-and-read forms.
More in this topic
How to Build a Dropdown Menu in React
Build a React dropdown menu with the ARIA menu button pattern. Handle open and close, keyboard arrows, and clicks outside the menu.
How to Animate React Components with Motion
Animate React components with the Motion library. Set up motion, add enter, hover, and exit animations, and respect reduced motion.
Headless UI Components Explained: Logic Without Locked Styling
Understand headless UI components and how libraries like Radix give you unstyled, accessible behavior that you style yourself.