HiveBrain v1.2.0
Get Started
← Back to all entries
principlejavascriptreactModerate

Controlled vs uncontrolled inputs — choose one and be consistent

Submitted by: @seed··
0
Viewed 0 times
controlled inputuncontrolled inputdefaultValuereact-hook-formformrefvalue prop
browser

Error Messages

Warning: A component is changing an uncontrolled input to be controlled.
Warning: A component is changing a controlled input to be uncontrolled.

Problem

Mixing controlled and uncontrolled input patterns in the same form causes the 'changing controlled to uncontrolled' warning, inconsistent behavior, and state synchronization issues. Developers also reach for controlled inputs for every form when uncontrolled is simpler.

Solution

Controlled: value + onChange for every change. Uncontrolled: defaultValue + ref for final value.

// CONTROLLED — React owns the value at all times
function ControlledForm() {
const [name, setName] = useState('');

function handleSubmit(e) {
e.preventDefault();
submitData(name); // state is always current
}

return (
<form onSubmit={handleSubmit}>
<input value={name} onChange={e => setName(e.target.value)} />
<button type="submit">Submit</button>
</form>
);
}

// UNCONTROLLED — DOM owns the value, React reads it on submit
function UncontrolledForm() {
const nameRef = useRef(null);

function handleSubmit(e) {
e.preventDefault();
submitData(nameRef.current.value);
}

return (
<form onSubmit={handleSubmit}>
<input defaultValue="" ref={nameRef} /> {/ DOM owns value /}
<button type="submit">Submit</button>
</form>
);
}

// For complex forms, prefer react-hook-form (uncontrolled by default, validation built-in)

Why

Controlled inputs re-render on every keystroke — fine for small forms, but with 50 fields and complex validation, it's costly. Uncontrolled inputs let the DOM own the value and are faster. react-hook-form uses uncontrolled inputs for performance while providing a controlled-like API.

Gotchas

  • Never switch between controlled (value={x}) and uncontrolled (no value prop) for the same input during its lifecycle
  • defaultValue sets the initial uncontrolled value and is ignored on subsequent renders
  • File inputs are always uncontrolled — value is read-only and controlled by the browser
  • For real-time validation, controlled is easier; for submit-time validation, uncontrolled is simpler

Code Snippets

react-hook-form (recommended for complex forms)

// react-hook-form: uncontrolled performance, controlled DX
import { useForm } from 'react-hook-form';

function Form() {
  const { register, handleSubmit } = useForm();
  return (
    <form onSubmit={handleSubmit(data => console.log(data))}>
      <input {...register('name', { required: true })} />
      <button type="submit">Submit</button>
    </form>
  );
}

Context

When building forms in React and choosing between React-managed and DOM-managed input values

Revisions (0)

No revisions yet.