Controlled vs Uncontrolled Forms in React

The difference between controlled and uncontrolled React forms is who owns each input's value. See both patterns and when each one is the right choice.

6 min read

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

AspectControlledUncontrolled
Source of truthReact stateThe DOM node
Value propvaluedefaultValue
Change handlingonChange updates stateOptional, read on demand
Reading the resultFrom stateFormData or a ref
Re-renders on typingYes, the field re-rendersNo 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.

App.jsxApp.jsx
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.

App.jsxApp.jsx
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 component

The ref points at the DOM node, and the handler reads its current value once when the form is submitted.

App.jsxApp.jsx
  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

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.
RunePowered by Rune AI

Frequently Asked Questions

Which is better, controlled or uncontrolled?

Neither is universally better. Controlled inputs win when the value drives other UI or needs live validation. Uncontrolled inputs win for simple submit-and-read forms and avoid re-rendering on every keystroke.

Does defaultValue update when I change it later?

No. defaultValue only sets the value on the first render. Changing it afterward does nothing. Use a value prop with onChange when React must keep driving the field.

Can I mix controlled and uncontrolled fields in one form?

Yes. Each field can have its own owner. Just keep one clear source of truth per field and avoid switching the same input between value and defaultValue.

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.