How is an "Uncontrolled Component" different?
Definition
An Uncontrolled Component is a component that keeps its own state (for example, an input field's value) inside the DOM, rather than in React state (
useState).
React does not manage its value directly here - it simply reads it when needed (via a ref or on form submit).
Example of an uncontrolled component
function LoginForm() {
const emailRef = useRef();
const passwordRef = useRef();
function handleSubmit(e) {
e.preventDefault();
console.log({
email: emailRef.current.value,
password: passwordRef.current.value,
});
}
return (
<form onSubmit={handleSubmit}>
<input ref={emailRef} type="email" placeholder="Email" />
<input ref={passwordRef} type="password" placeholder="Password" />
<button type="submit">Log in</button>
</form>
);
}Here:
- the
<input>stores its own value (inside the DOM);- React doesn't know what the user is typing;
- on submit, we pull the value out of the DOM via
ref.
Difference from a controlled component
Controlled Component
function Controlled() {
const [name, setName] = useState('');
return (
<input
value={name}
onChange={(e) => setName(e.target.value)} // React controls the value
/>
);
}React is the "single source of truth".
Uncontrolled Component
function Uncontrolled() {
const inputRef = useRef();
return (
<input ref={inputRef} /> // the value lives in the DOM
);
}The DOM is the source of truth, React just observes.
Key differences
| Criterion | Controlled | Uncontrolled |
|---|---|---|
| Where the value is stored | In React state | Inside the DOM |
| How it's updated | Via onChange -> setState | The user types directly |
| Does React know the current value? | Yes | No (until requested via ref) |
| Data management | Fully controlled by React | React "asks" the DOM when needed |
| Validation / masks / autofill | Possible in real time | Only on submit |
| Convenience for complex forms | High | Limited |
| Performance | Slightly lower (frequent renders) | Slightly higher (React doesn't track every change) |
When to use Uncontrolled Components
They fit simple, isolated forms that don't need an instant reaction to input. For example:
- a subscription form with one field and a button;
- a search box where the value is read only on submit;
- integration with third-party libraries that manage the DOM themselves (
input[type=file], third-party widgets, etc.).
A real-world example (input type="file")
function FileUploader() {
const fileRef = useRef();
function handleUpload() {
const file = fileRef.current.files[0];
console.log(file.name);
}
return (
<div>
<input type="file" ref={fileRef} /> {/* React does not manage this */}
<button onClick={handleUpload}>Upload</button>
</div>
);
}
<input type="file" />is always uncontrolled, because React has no direct access to file data. Here the DOM controls the value.
Sometimes you can mix the two
Sometimes a hybrid approach is convenient:
- set an initial value on mount;
- don't manage it through state afterward.
<input defaultValue="Hello" /> // Uncontrolled with initial dataThe
defaultValueattribute (ordefaultChecked) sets the starting value, but after that React doesn't track changes.
Summary
| Property | Controlled Component | Uncontrolled Component |
|---|---|---|
| Source of truth | React state | DOM |
| Input management | React controls it | The browser controls it |
| Reading the value | Via state | Via ref |
| Reaction to changes | In real time | Only on an event |
| Use case | Complex forms, validation, dynamic behavior | Simple forms, integrations, <input type="file"> |
| Attributes | value, onChange | defaultValue, ref |
Main idea: A controlled component: React "holds the wheel". An uncontrolled one: "the browser drives itself", and React just watches.
Short Answer
Interview readyA concise answer to help you respond confidently on this topic during an interview.