How to fix A component is changing an uncontrolled input to be controlled in React
React complains when an input starts with no value (uncontrolled) and later receives a value prop. Keeping inputs consistently controlled or using defaultValue avoids the warning and keeps form state predictable.
Quick fix
Fixes A component is changing an uncontrolled input to be controlled
const [message, setMessage] = useState('');
const [agreed, setAgreed] = useState(false);- Always initialize state with a valid value
- Coerce optional props or API data before passing to value
- Delay rendering the controlled input until the data is ready
- Use defaultValue/defaultChecked for truly uncontrolled inputs
const [message, setMessage] = useState('');const [agreed, setAgreed] = useState(false);A component is changing an uncontrolled input to be controlled
What this error means
This warning means React detected an input (or checkbox/select) that began without a value or checked prop and then received one on a later render. React treats that as an uncontrolled component switching to a controlled one, which is not allowed because it causes glitches and breaks the single source of truth for the field. The usual culprit is that the value prop is undefined on the first render (often because you skipped the initial state or data hasn't loaded yet), and then becomes a string once the user types or remote data arrives. React expects the prop to remain defined throughout the component's lifetime so it can keep the DOM in sync. If you truly never want React to control the input, use defaultValue/defaultChecked instead. This warning also shows up for checked on radios/checkboxes and for value on selects and textareas. The fix is to keep using the same paradigm (controlled vs uncontrolled) and sanitize any undefined values before passing them to the input.
Typical symptoms
- Console warning: "A component is changing an uncontrolled input to be controlled"
- Controlled input renders correctly at first but warning appears once data loads or user types
- Initial render leaves the field empty because the value prop was undefined
- Form fields flicker between uncontrolled behavior and controlled updates
- Autocomplete / form resets stop working because React loses track of the input type
- Similar warning also appears for checkboxes (checked) and selects (value)
Common causes
- useState() without an initial value leaves the state undefined until the user types
- Value comes from props/api that aren't ready yet (e.g. value={user?.name})
- Conditional rendering passes undefined for optional fields when the prop is absent
- Passing null or undefined to value/reset logic, then later providing a string
- Mixing controlled value with defaultValue on the same element during different renders
- Resetting the form by setting state fields to undefined instead of an empty string
- Asynchronous data arrives after the first render, switching value from undefined to real data
How to fix "A component is changing an uncontrolled input to be controlled"
Set the state you bind to value (or checked for radios/checkboxes) to a concrete value from the start:
const [message, setMessage] = useState('');
const [agreed, setAgreed] = useState(false);Even if the API result arrives later, React never sees undefined as the value, so the warning never fires. If you use TypeScript, type the state explicitly (useState<string>('')).
Guard against undefined responses by falling back to an empty string:
<input value={user?.nickname ?? ''} onChange={(e) => setNickname(e.target.value)} />You can also use logical OR (||) when you truly expect an empty string fallback. This keeps value defined even if the prop is missing or null.
If you fetch data before rendering a form, wait for the payload with an early return:
if (!user) {
return <p>Loading…</p>;
}
return (
<input value={user.email} onChange={(e) => setEmail(e.target.value)} />
);This avoids mounting the input with an undefined value while you still treat it as controlled.
When you do not need to update React state on each keystroke, make the input uncontrolled:
<input defaultValue="initial" ref={inputRef} />Only read the ref.current.value when you need it (e.g., on submit). Do not pair defaultValue with value on the same element, because that mixes paradigms.
If you reset form state, keep the inputs controlled by resetting to empty values:
const RESET_STATE = { message: '', email: '' };
setFormState(RESET_STATE);Avoid resetting fields to undefined/null, which would temporarily drop them from control and trigger the warning again.
When rendering fields from an array or nested object, provide fallbacks per item:
{fields.map((field) => (
<input
key={field.id}
value={field.value ?? ''}
onChange={(e) => updateField(field.id, e.target.value)}
/>
))}This prevents sparse data from passing undefined for some items while others already have values.
Advanced notes
TypeScript tip: Enable strict-null-checks and type your form state so the compiler demands an initial string/boolean. React 18+ forms: Hooks and concurrent behavior didn't change the warning; React still enforces consistent control. Other elements: The same guardrails apply to <textarea> and <select>. Always treat checked on radios/checkboxes the same way you treat value on text inputs.
Frequently asked questions
- What does "A component is changing an uncontrolled input to be controlled" mean?
- This warning means React detected an input (or checkbox/select) that began without a value or checked prop and then received one on a later render. React treats that as an uncontrolled component switching to a controlled one, which is not allowed because it causes glitches and breaks the single source of truth for the field. The usual culprit is that the value prop is undefined on the first render (often because you skipped the initial state or data hasn't loaded yet), and then becomes a string once the user types or remote data arrives.
- How do I fix "A component is changing an uncontrolled input to be controlled"?
- React complains when an input starts with no value (uncontrolled) and later receives a value prop. Keeping inputs consistently controlled or using defaultValue avoids the warning and keeps form state predictable.
- What causes "A component is changing an uncontrolled input to be controlled"?
- useState() without an initial value leaves the state undefined until the user types Value comes from props/api that aren't ready yet (e.g. value={user?.name}) Conditional rendering passes undefined for optional fields when the prop is absent
- Is the "A component is changing an uncontrolled input to be controlled" error serious?
- It is a medium-severity error — more of a blocker than a risk. The steps above resolve it.
Official resources & further reading
- 📚React Official Documentation
- 📖React: Input component reference(Official Docs)
- 📖React: Uncontrolled components(Official Docs)