Beginner3 questionsFull Guide

React Controlled vs Uncontrolled Components — Complete Interview Guide

Master the difference between controlled and uncontrolled form components — when React owns the value vs when the DOM does, how to avoid the most common switching bug, and why top form libraries make opposite choices.

The Mental Model

A controlled component is like a puppet — React holds every string. Every keystroke flows through an onChange handler into React state, and the input always shows exactly what React says it should. An uncontrolled component is like a free actor — it holds its own state inside the DOM, and you only ask what it's doing when you actually need to know, using a ref. The core question is: who is the single source of truth for the input's value — React state (controlled) or the DOM itself (uncontrolled)?

The Explanation

Controlled Components — React Owns the Value

A controlled input has two required pieces: a value prop tied to React state, and an onChange handler that updates that state. Every keystroke the user makes flows through the handler, updates state, triggers a re-render, and the input displays the new state value. The DOM never independently holds the current value — React state is always the source of truth.

function ControlledSearch() {
  const [query, setQuery] = useState('');

  return (
    <input
      type="text"
      value={query}                         // React state drives the displayed value
      onChange={e => setQuery(e.target.value)} // every keystroke updates state
    />
  );
}

Because React state is always current, you can read query at any moment without touching the DOM. This makes instant validation, character counters, conditional UI, and programmatic resets straightforward.

Uncontrolled Components — The DOM Owns the Value

An uncontrolled input manages its own value inside the DOM — React doesn't know the current value unless it explicitly reads it via a ref. You set the starting value with defaultValue (not value), and the DOM takes over from there.

function UncontrolledForm() {
  const nameRef = useRef(null);

  function handleSubmit(e) {
    e.preventDefault();
    console.log(nameRef.current.value); // read on demand
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        ref={nameRef}
        defaultValue="Alice"  // sets initial DOM value; DOM controls it after that
      />
      <button type="submit">Submit</button>
    </form>
  );
}

Uncontrolled inputs don't re-render on every keystroke because React is completely unaware of the changes. This makes them significantly faster for large forms with many fields.

The Critical Rule: Never Switch Between the Two

React tracks whether an input is controlled (has a value prop) or uncontrolled (no value prop) from the first render. Switching between them — by passing undefined as the value — causes a React warning and unpredictable behaviour:

// ❌ Bug: undefined on first render (uncontrolled), string later (controlled)
<input value={user?.name} />

// ✅ Fix: always provide a string — controlled from the first render onwards
<input value={user?.name ?? ''} />
If value can ever be undefined or null, always provide a fallback empty string. This is the most common controlled-component bug in real codebases.

textarea and select — Same Pattern, Different Look

React normalises <textarea> and <select> to follow the same controlled/uncontrolled API as <input>:

// Controlled textarea
<textarea value={bio} onChange={e => setBio(e.target.value)} />

// Controlled select — value on the <select>, not on <option>
<select value={country} onChange={e => setCountry(e.target.value)}>
  <option value="in">India</option>
  <option value="us">USA</option>
</select>

File Inputs — Always Uncontrolled

File inputs are always uncontrolled — this is a browser security restriction, not a React limitation. The browser will never allow JavaScript to programmatically set a file input's value. Read the selected file through a ref or the event object:

// ❌ React will warn — file inputs cannot have a value prop
<input type="file" value={file} />

// ✅ Always read via ref or event
const fileRef = useRef(null);

function handleUpload() {
  const file = fileRef.current.files[0];
  upload(file);
}

<input type="file" ref={fileRef} />

When to Use Each

Use controlled when you need:

  • Instant validation or feedback as the user types
  • Conditional UI that depends on the current input value (character counter, submit button state)
  • Programmatically setting, clearing, or resetting the value
  • Syncing the input value with another part of the UI

Use uncontrolled when:

  • You have a large form (50+ fields) and keystroke re-renders are a measurable bottleneck
  • You only need the values at submit time, not during typing
  • Integrating with non-React code or third-party libraries that manage their own input state

How Form Libraries Choose

React Hook Form is built on uncontrolled inputs — fields register via refs, values are read on submit, and only fields with errors re-render. This makes it extremely fast for large forms. Formik uses controlled inputs — every field value lives in Formik's state, enabling per-field validation and easy cross-field logic at the cost of per-keystroke re-renders.

Common Misconceptions

⚠️

Many developers think uncontrolled inputs are the inferior, 'wrong' way — they're a deliberate trade-off. React Hook Form, one of the most widely used React libraries, is built entirely on uncontrolled inputs because they avoid per-keystroke re-renders across the entire form.

⚠️

Many developers use value={someUndefinedValue} thinking this makes the input uncontrolled — React treats an initial value of undefined as 'no value prop' (uncontrolled), but if value later becomes a string the input switches to controlled mid-lifecycle. Always use value={someValue ?? ''} to stay consistently controlled.

⚠️

Many developers try to set a file input's value prop — file inputs are always uncontrolled by browser security design. The browser prevents scripts from setting file input values so a webpage can't silently pre-select files. Read files via ref or event.target.files, always.

⚠️

Many developers think defaultValue and value are just different names for the same thing — defaultValue sets the DOM value once on mount and hands control to the DOM (uncontrolled). value sets the DOM value from React state on every render (controlled). Confusing them is why inputs appear to 'forget' what the user typed.

⚠️

Many developers think controlled inputs always cause performance problems — the performance difference is negligible for forms with fewer than ~20 fields. Only optimise with uncontrolled inputs when you've actually measured a keystroke-render bottleneck, not as a premature optimisation.

⚠️

Many developers add onChange to an input without a value prop thinking that makes it controlled — an input without a value prop is uncontrolled regardless of how many event handlers it has. The value prop is what makes it controlled, nothing else.

Where You'll See This in Real Code

Search-as-you-type: a search bar that filters results on every keystroke needs a controlled input — React reads query from state on every keystroke to call the filter function or debounced API.

Character counter: 'You have X characters remaining' requires a controlled input to know the current length on every keystroke without querying the DOM.

Multi-step form wizard: each step passes values to the next via React state — controlled inputs make this natural since values already live in state and can be freely read, validated, and reset.

React Hook Form at scale: a checkout form with 30+ fields (shipping, billing, card details) uses uncontrolled inputs via register() so zero re-renders occur on keystroke — only the field with a validation error re-renders.

File upload UI: drag-and-drop upload components use an uncontrolled file input (required by the browser) alongside a separate useState for the selected file preview — the input is uncontrolled, the preview state is React-controlled.

Autofill edge cases: browser autofill and password managers set input values by directly writing to the DOM, bypassing React's onChange. Controlled inputs handle this via a synthetic 'input' event that React re-raises; some form libraries add specific autofill workarounds.

Interview Cheat Sheet

  • Controlled: value={state} + onChange={setState} — React state is source of truth, re-renders on keystroke
  • Uncontrolled: defaultValue={initial} + ref={ref} — DOM is source of truth, read via ref.current.value
  • Never switch between controlled and uncontrolled — always provide value={someState ?? ''} to avoid undefined
  • textarea: same API — value + onChange for controlled, defaultValue + ref for uncontrolled
  • select: value prop goes on &lt;select&gt;, not on &lt;option&gt;
  • File input: always uncontrolled — browser security prevents setting value programmatically
  • Controlled use cases: instant validation, character count, programmatic reset, conditional UI
  • Uncontrolled use cases: large forms, submit-only reads, non-React integration
  • React Hook Form = uncontrolled (performant); Formik = controlled (simple validation)
  • Resetting controlled form: setState(initialValues); Resetting uncontrolled: form.reset() or change the component's key
💡

How to Answer in an Interview

  • 1.Lead with the source-of-truth framing: 'In a controlled component, React state is the single source of truth — every change goes through state. In an uncontrolled component, the DOM holds the value and you read it via a ref when needed.' This is the conceptual answer; implementation details can follow.
  • 2.Mention the undefined-switching bug proactively — it signals real-world experience: 'A very common bug is value={user?.name} where user is null on first render. The input starts uncontrolled (undefined = no value prop) then becomes controlled when user loads. React warns and behaves unpredictably. Always fall back to an empty string.'
  • 3.File inputs are always uncontrolled — stating this unprompted shows you know browser constraints, not just React: 'File inputs are a special case — the browser won't allow programmatic value setting for security reasons, so they're always uncontrolled regardless of what you do in React.'
  • 4.Connect form libraries to the concept: 'React Hook Form is fast because it uses uncontrolled inputs — zero re-renders on keystroke, values read only at submit. Formik uses controlled inputs — more re-renders, but easier cross-field validation. Understanding controlled vs uncontrolled is why you can reason about why one is faster.'
  • 5.If asked how to reset a form: 'For controlled forms, reset state to initial values with setState. For uncontrolled forms, call form.reset() on the DOM form element. Another option for both is to change the form component's key — forcing React to remount it from scratch.'
  • 6.Don't over-engineer: 'For most forms under 20 fields, I use controlled inputs — the re-render cost is negligible and the simplicity of having values in state is worth it. I only reach for uncontrolled or React Hook Form when I've actually measured a performance problem.'
📖 Deep Dive Articles
Top 50 React Interview Questions (2025 Edition)15 min read

Practice Questions

3 questions
#01

What is the difference between a controlled and uncontrolled component?

EasyReact Fundamentals💡 Controlled = React owns the value; uncontrolled = DOM owns it (accessed via ref)
#02

What is react-hook-form and why is it better than manual controlled forms?

EasyForms PRO💡 Uncontrolled inputs with ref-based validation — zero re-renders per keystroke, minimal boilerplate
#03

Controlled vs uncontrolled — who owns the value?

MediumComponent Patterns
MetaFlipkartRazorpay

Related Topics

useState Hook — Complete React Interview Guide
Beginner·4–8 Qs
React Rendering & Performance Interview Questions
Advanced·4–8 Qs
useRef Hook — Complete React Interview Guide
Beginner·4–8 Qs
🎯

Can you answer these under pressure?

Reading answers is not the same as knowing them. Practice saying them out loud with AI feedback — that's what builds real interview confidence.

Practice Free →Try Output Quiz