Controlled vs Uncontrolled Components
A controlled input has its value driven by React state ( value + onChange ) — React is the source of truth. An uncontrolled input keeps its value in the DOM, and you read it on demand with a ref ( defaultValue ). By the end you'll know which to reach for and how to avoid the dreaded "switching between controlled and uncontrolled" warning.
Learn Controlled vs Uncontrolled Components in our free React course — a beginner-friendly interactive lesson with runnable examples, a practice exercise and…
Part of the free React course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
1️⃣ Controlled Inputs
In a controlled input you bind value to state and update that state in onChange . The input can only show what state holds, which gives you total control: validate, format, or transform every keystroke before it appears.
The demo models a controlled handler that transforms input (here, to uppercase) before storing it in state:
Your turn — write a controlled handler that keeps only digits (a numeric field):
2️⃣ Uncontrolled Inputs
An uncontrolled input lets the DOM keep its own value. You don't track each keystroke in state; instead you grab the value when you need it using a ref . Set the starting value with defaultValue (not value ). This is simpler and avoids a re-render per keystroke.
The demo models the DOM node holding its own value, read only at submit time:
3️⃣ Choosing — and the Switch Warning
Reach for controlled when you need live validation, conditional buttons, instant formatting, or when other UI depends on the value. Reach for uncontrolled for simple forms or when you must (file inputs are always uncontrolled). The cardinal sin is switching mid-life: if value starts undefined and later becomes a string, React warns.
Fix it by initializing controlled state to a defined value (like "" ), and never feed value={' '} .
These lines build a controlled input. Put them in a correct order:
1) Which prop makes an input controlled: value or defaultValue ?
value (bound to state). defaultValue sets only the initial value of an uncontrolled input.
2) You start with useState() and bind it to value . What goes wrong?
The value starts undefined (uncontrolled) then becomes defined (controlled), triggering React's switch warning. Initialize to "" .
A file input ( ) — its value is read-only and can't be set from React state.
📋 Quick Reference
A controlled input is perfect when other UI depends on the value. Model an onChange that stores the text, then compute the remaining characters out of a 10-char limit. Predict the result before running.
Practice quiz
What makes an input 'controlled' in React?
- It uses defaultValue
- It has no onChange handler
- Its value is driven by React state via value + onChange
- It is wrapped in a ref
Answer: Its value is driven by React state via value + onChange. A controlled input binds value={state} and updates state in onChange — React is the source of truth.
Where does an uncontrolled input keep its value?
- In the DOM, read on demand (usually via a ref)
- In React state
- In localStorage
- In a context provider
Answer: In the DOM, read on demand (usually via a ref). An uncontrolled input keeps its value in the DOM; you read it when needed, typically with a ref.
Which prop sets the initial value of an uncontrolled input?
- value
- initialValue
- startValue
- defaultValue
Answer: defaultValue. Uncontrolled inputs use defaultValue for the starting value; value would make it controlled.
A controlled input shows but you can't type in it. What's the likely cause?
- Missing defaultValue
- value is set but there's no onChange handler
- The input is inside a form
- Too many re-renders
Answer: value is set but there's no onChange handler. A controlled input needs both value and onChange; with value but no onChange it becomes read-only.
What triggers React's 'changing an uncontrolled input to be controlled' warning?
- An input's value going from undefined to a defined value (or vice versa)
- Using onChange
- Using defaultValue
- Rendering inside a list
Answer: An input's value going from undefined to a defined value (or vice versa). Switching value between undefined and defined flips the input's mode. Pick one and stick with it.
How do you avoid the controlled/uncontrolled switch warning?
- Start state as undefined
- Always use defaultValue and value together
- Initialize controlled state to a defined value like ""
- Remove onChange
Answer: Initialize controlled state to a defined value like "". Initialize controlled state to a defined value (e.g. useState("")) so value is never undefined.
Which input type must always be uncontrolled?
- A text input
- A file input
- A checkbox
- A select
Answer: A file input. A file input's value is read-only and can't be set from React state, so it must be uncontrolled.
When is a controlled input the better choice?
- For simple forms you read only on submit
- When integrating non-React code
- For file uploads
- When you need live validation, formatting, or other UI depending on the value
Answer: When you need live validation, formatting, or other UI depending on the value. Controlled inputs let you validate, format, or disable based on every keystroke and drive other UI.
How do you read an uncontrolled input's current value?
- From state
- From ref.current.value
- From e.preventDefault()
- From defaultValue
Answer: From ref.current.value. Attach a ref and read ref.current.value (e.g. on submit) to get the DOM-held value.
In a controlled input, why can you transform text as the user types?
- Because the DOM stores the value
- Because defaultValue formats it
- Because onChange computes the next state, and value only shows what state holds
- You cannot transform controlled input
Answer: Because onChange computes the next state, and value only shows what state holds. Since state drives value, your onChange can transform the input (uppercase, strip non-digits) before storing it.