
Last updated: Apr 6, 2024
Reading timeยท3 min

The warning "A component is changing an uncontrolled input to be controlled"
occurs when an input value is initialized to undefined but is later changed to
a different value.
To fix the warning, initialize the input value to an empty string, e.g.
value={message || ''}.

Here is an example of how the error occurs.
import {useState} from 'react'; const App = () => { // ๐๏ธ didn't provide an initial value for `message` const [message, setMessage] = useState(); const handleChange = event => { setMessage(event.target.value); }; // โ๏ธ Warning: A component is changing an uncontrolled input to be controlled. This is likely caused by the value changing from undefined to a defined value, which should not happen. return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message} /> </div> ); }; export default App;
The issue is that the message state variable is initially set to undefined
because we didn't pass an initial value for it to the
useState hook.
undefinedOne way to solve the error is to provide a fallback if the input value is
undefined.
import {useState} from 'react'; const App = () => { const [message, setMessage] = useState(); const handleChange = event => { setMessage(event.target.value); console.log(event.target.value); }; // ๐๏ธ value={message || ''} return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message || ''} /> </div> ); }; export default App;

We used the
logical OR (||)
operator, which returns the value to the right if the value to the left is falsy
(e.g. undefined).
message variable stores an undefined value, we return an empty string as a fallback.useState hookAn alternative solution is to
pass an initial value for the state
variable to the useState hook.
import {useState} from 'react'; const App = () => { // ๐๏ธ Pass an initial value to the useState hook const [message, setMessage] = useState(''); const handleChange = event => { setMessage(event.target.value); console.log(event.target.value); }; return ( <div> <input type="text" id="message" name="message" onChange={handleChange} value={message} /> </div> ); }; export default App;

Passing an initial value to the useState hook gets rid of the warning because
now the message variable doesn't change from undefined to having a value.
The warning is caused because when the message variable is initialized without
a value, it is set to undefined.
Passing a prop like value={undefined} is the same as not passing the value
prop at all.
value prop is now passed to the input field and the input changes from uncontrolled to controlled which is not allowed.defaultValue prop for uncontrolled componentsNote that if you use an uncontrolled input field, you should use the
defaultValue prop instead of value.
import {useRef} from 'react'; const App = () => { const inputRef = useRef(null); function handleClick() { console.log(inputRef.current.value); } return ( <div> <input ref={inputRef} type="text" id="message" name="message" defaultValue="Initial value" /> <button onClick={handleClick}>Log message</button> </div> ); }; export default App;

The example above uses an uncontrolled input. Notice that the input field
doesn't have an onChange prop or value set.
defaultValue prop. However, this is not necessary and you can omit the prop if you don't want to set an initial value.When using uncontrolled input fields, we access the input using a ref.
Every time the user clicks on the button in the example, the value of the uncontrolled input gets logged.
You shouldn't set the value prop on an uncontrolled input (an input field that
doesn't have an onChange handler) because that would make the input field
immutable and you wouldn't be able to type in it.