- Controlled: the input's value comes from React state and every keystroke goes through onChange. React is the single source of truth.
- Uncontrolled: the browser keeps the value, and you read it when you need it, for example on submit through FormData or a ref.
function Signup() {
const [email, setEmail] = useState('');
const valid = /^[^@\s]+@[^@\s]+\.[a-z]{2,}$/i.test(email);
return (
<form>
<label htmlFor="em">College email</label>
<input id="em" type="email" value={email} onChange={e => setEmail(e.target.value)} />
<button disabled={!valid}>Sign up</button>
</form>
);
}
render(<Signup />);<form><label for="em">College email</label><input id="em" type="email" value=""/><button disabled="">Sign up</button></form>When to use which
- Use controlled inputs when the UI reacts as the user types: live validation, a disabled button, formatting, character counters.
- Use uncontrolled inputs (defaultValue, then read FormData on submit) for simple forms where you only need the values at the end. It is less code and fewer renders.
The common warning
"A component is changing an uncontrolled input to be controlled" means the value started as undefined and later became a string. Initialise state with an empty string, as with useState('') above, never with undefined. Use htmlFor instead of for on labels in JSX.
#react#forms#controlled components#inputs
Sources and further reading
Practise this as an interview question
Written by the UniCircle team, checked by an editor on 22 Oct 2026. It is not official policy of any university. Exam patterns and rules change; confirm dates and rules on the official website.
