What is the difference between controlled and uncontrolled components in React?
The short answer
In a controlled component, React state is the single source of truth — the component's behavior is fully driven by props or state from the parent. In an uncontrolled component, the component manages its own internal state, and you read the value only when you need it. This concept applies to any component (modals, accordions, dropdowns), but it comes up most often with form inputs.
The core concept — who owns the state?
The idea behind controlled vs uncontrolled is simple — who is in charge of the state?
A controlled component is like a puppet on strings — the parent tells it exactly what to show and what to do. An uncontrolled component is like an actor — it does its own thing internally, and you only check in when you need to know what happened.
This pattern is everywhere in React. A modal can be controlled (parent passes isOpen prop) or uncontrolled (modal tracks its own open/closed state). A dropdown can be controlled (parent passes selectedValue) or uncontrolled (dropdown tracks selection internally).
But the most common place you will see this is with form inputs. Let me explain both patterns using forms.
Controlled form inputs
In a controlled input, you store the value in React state and update it on every change. React state is always in sync with what the user sees on screen.
function LoginForm() { const [email, setEmail] = useState(''); const handleChange = (event) => { setEmail(event.target.value); }; const handleSubmit = (event) => { event.preventDefault(); console.log('Submitted:', email); }; return ( <form onSubmit={handleSubmit}> <input type="email" value={email} onChange={handleChange} /> <button type="submit">Log in</button> </form> );}Here is what happens step by step:
- The input's
valueis set toemailstate, which starts as an empty string - When the user types a character, the
onChangehandler fires handleChangecallssetEmailwith the new value- React re-renders the component with the updated state
- The input displays the new value from state
The input never has a value that React does not know about. That is why it is called "controlled" — React is in full control.
This gives you power. You can validate on every keystroke, transform the input (like forcing uppercase or stripping non-digit characters), or disable a submit button until the form is valid.
Uncontrolled form inputs
In an uncontrolled input, the DOM handles the value. Instead of tracking every keystroke in state, you use a ref to read the value when you need it.
function LoginForm() { const emailRef = useRef(null); const handleSubmit = (event) => { event.preventDefault(); console.log('Submitted:', emailRef.current.value); }; return ( <form onSubmit={handleSubmit}> <input type="email" ref={emailRef} /> <button type="submit">Log in</button> </form> );}No useState, no onChange, no re-renders on every keystroke. The browser keeps track of what the user typed. When the form is submitted, you reach into the DOM using the ref and grab the value.
You can set an initial value using defaultValue instead of value:
<input type="email" ref={emailRef} defaultValue="user@example.com"/>defaultValue sets the starting value but does not control it after that. The user can change it freely, and React does not track those changes.
When to use which
Use controlled when:
- You need to validate or transform input on every keystroke
- You need to disable a submit button until the form is valid
- You need to show real-time feedback as the user types
- Multiple inputs depend on each other's values
Use uncontrolled when:
- You have a simple form and only need the values on submit
- You want to avoid re-renders on every keystroke for performance
- You are integrating with non-React code or third-party libraries
- You are working with file inputs (
<input type="file" />is always uncontrolled in React because its value is read-only)
In practice, most React applications use controlled inputs as the default. The slight performance cost of re-rendering on every keystroke is rarely noticeable, and having full control over the input is usually worth it.
Common Pitfalls
A common mistake candidates make is mixing controlled and uncontrolled patterns on the same input. If you set value on an input but forget to add onChange, the input becomes read-only — the user types but nothing changes because React keeps resetting it to the state value. Another mistake is switching from uncontrolled to controlled during the component's lifetime (starting with value={undefined} then changing to value={someState}). React will warn you about both of these.
Interview Tip
When answering this question, start with the general concept — who owns the state, the parent or the component? Then explain both patterns using form inputs since that is the most common use case. But do mention that the same idea applies to other components like modals and dropdowns. This shows the interviewer you understand the underlying pattern, not just the form-specific use case.
Why interviewers ask this
This question tests your understanding of where state should live in React. It is really about component design — should the parent control the behavior, or should the component manage itself? A candidate who can explain both approaches, knows when each makes sense, and understands the tradeoffs (control vs simplicity, re-renders vs ease of use) shows they think about building well-designed components, which is what companies care about.