Controlled vs uncontrolled inputs


I know there are a lot of articles regarding react forms. But, it doesn't hurt if I say something again in a very short explanation about react form input types. We all know that there two kinds of form inputs in react namely: controlled and uncontrolled inputs.
Controlled inputs
Controlled inputs accept their current value as a prop and a callback to change that value. That implies that the value of the input has to live in the React state somewhere. Typically, the component that renders the input (like a form component) saves that in its state:
const Form = () => {
const [value, setValue] = useState("");
const handleChange = (e) => {
setValue(e.target.value)
}
return (
<form>
<input
value={value}
onChange={handleChange}
type="text"
/>
</form>
);
};
Every time you type a new character, the handleChange function is executed. It receives the new value of the input, and then it sets it in the state. So, the Form component always has the input's current value without needing to ask for it explicitly.
As a result, your data (React state) and UI (input tags) are always in sync. Another implication is that forms can respond to input changes immediately, for example, by:
Instant validation per field
Disabling the submit button unless all fields have valid data
Enforcing a specific input format, like phone or credit card numbers
Sometimes you will find yourself not needing any of that. In that case uncontrolled could be a more straightforward choice.
Uncontrolled inputs
Unlike the controlled inputs where data is handled by the react component, in uncontrolled component, data is handled by the DOM itself. So, if we don't have controlled over its state, how do we access its value? To access the value of an uncontrolled input, we use the React Ref hook. For example, in the code below we use, the Ref hook to access the current value of the input
const Form = () => {
const inputRef = useRef(null);
const handleSubmit = () => {
const inputValue = inputRef.current.value;
// Do something with the value
}
return (
<form onSubmit={handleSubmit}>
<input ref={inputRef} type="text" />
</form>
);
};
Let me wrap up my little article, by mentioning that there are some specific form inputs that are always uncontrolled, like the file input tag.
In React, an is always an uncontrolled component because its value is read-only and can't be set programmatically.
const Form = () => {
const fileInput = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
const files = fileInput.current.files;
// Do something with the files here
}
return (
<form onSubmit={handleSubmit}>
<input
ref={fileInput}
type="file"
/>
</form>
);
};
React recommends using controlled inputs over uncontrolled inputs, but let me summarise in the table below.
References: React docsReact forms by Gosha
Subscribe to my newsletter
Read articles from Brhane G. Ashebr directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by

Brhane G. Ashebr
Brhane G. Ashebr
๐จโ๐ป IT Professional | Security Research Analyst | Vulnerability Analyst ๐ Passionate about enhancing the security of PHP-based applications, including WordPress, Drupal, and Joomla. ๐ 6+ years of experience in security research, patch development, and vulnerability analysis for open-source projects. ๐ก๏ธ Advocate for open-source security, performing meticulous code reviews and thorough testing to ensure stability and reliability. โ๏ธ AWS Certified Solutions Architect with hands-on experience designing and deploying scalable, secure cloud solutions. ๐ Former SOC Analyst, specializing in monitoring, threat detection, and incident response. ๐ค Intermediate experience in LLM fine-tuning and AI agent development, leveraging AI for innovative solutions in security and automation. ๐ฏ Currently building a monetizable portfolio and side projects that bridge cutting-edge security practices, AI, and real-world solutions. ๐ก On a mission to empower developers, businesses, and website owners with secure, reliable, and AI-driven applications.