React
Controlled and uncontrolled forms: real costs
A controlled field keeps its value in React state, an uncontrolled one leaves it in the DOM: what changes is renders, validation and files.
Key points
- A controlled field keeps its value in React state; an uncontrolled one keeps it in the DOM.
- Controlled state costs one render per keystroke; an uncontrolled field costs none until submit.
- File inputs stay uncontrolled because the browser does not let you set their value.
A controlled form keeps the value in React state and updates it on every keystroke; an uncontrolled form leaves the value in the DOM and reads it at submit.
Who owns the value
In a controlled form the value lives in useState: React is the single source of truth, so the field can be validated and formatted as you type. In an uncontrolled form the value lives in the HTML element: defaultValue sets the starting value, and FormData or a ref read it at the end. The difference is not style, it is who is in charge.
The two schemes, side by side
function Controlled() {
const [email, setEmail] = useState("");
return setEmail(e.target.value)} />;
}
function Uncontrolled() {
return ;
}
The first scheme re-renders the component on every character; the second leaves that to the browser and costs no render until submit.
The cost you pay
- Render per keystroke: when the state lives in the parent, one controlled field in a fifty-field form updates all of it on every letter.
- Instant validation: only state can show an error while the reader types, without reading the DOM.
- Files and native fields: a file input stays uncontrolled, because the browser does not let you set its value.
A project to start from
npm create vite@latest form-demo -- --template react
cd form-demo
npm install
npm run dev
Vite, released under the MIT licence, creates the project and starts the development server; you change the field in src/App.jsx without touching the configuration.
Live records in the catalogue
Three components show the two schemes at work: credit-card-form, with fields controlled by a mask, login-form and otp-input. To browse by category start from 111,985 components.
The limitation
Neither scheme wins every time. Controlled state in a large form moves the cost onto React: every keystroke re-renders, and without local state or memo the field becomes slow. The uncontrolled scheme loses instant validation and dependent fields, because React cannot see the value until you ask for it.
Where to continue
The general model is in what React is; the measured comparison of form libraries is in React form libraries; the choice between the two most used frameworks is in Vue 3 vs React.
Frequently asked questions
Which scheme suits a login form?
Usually controlled. Two fields and a button cost few renders, and instant validation is worth more than the saving.
Can I mix controlled and uncontrolled fields?
Yes, and it is often the right call. The search box and file inputs stay uncontrolled, the rest goes into state or a form library.
Why can a file input not be controlled?
Because the browser does not allow setting the value of a file input, for security. You read it from FormData or a ref.
Is a slow controlled input a browser problem?
No, a component problem. State placed too high re-renders the whole form: move it into the field or use react-hook-form.
Do large forms need react-hook-form?
No, but it avoids the per-keystroke cost with uncontrolled fields and per-field subscriptions. It ships under the MIT licence.