What is the difference between controlled and uncontrolled components in React?

ReactMetaGoogleAmazon

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:

  1. The input's value is set to email state, which starts as an empty string
  2. When the user types a character, the onChange handler fires
  3. handleChange calls setEmail with the new value
  4. React re-renders the component with the updated state
  5. 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.