Handling Forms in React: Controlled vs Uncontrolled Components

Forms are a crucial part of web applications, and React provides two main ways to handle them: Controlled and Uncontrolled components. Understanding the difference between these approaches helps you choose the right one for your use case.
In this article, we’ll compare Controlled and Uncontrolled components in React, discuss their pros and cons, and provide practical code examples.
1. Controlled Components
In a controlled component, form data is handled by React state. Every keystroke or input change updates the state, making React the single source of truth.
How It Works:
Form inputs are tied to React state (
useState).Changes trigger state updates via
onChange.The state value is passed back to the input via
valueprop.
Example:
import { useState } from 'react';
function ControlledForm() {
const [name, setName] = useState('');
const handleSubmit = (e) => {
e.preventDefault();
alert(`Submitted Name: ${name}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
/>
</label>
<button type="submit">Submit</button>
</form>
);
}
Pros of Controlled Components:
✅ Predictable state management – React fully controls the form state.
✅ Easy validation – Validate inputs before submission.
✅ Real-time updates – UI reacts immediately to changes.
Cons of Controlled Components:
❌ More boilerplate – Requires useState and onChange for each input.
❌ Slight performance overhead – Re-renders on every keystroke (usually negligible).
2. Uncontrolled Components
In an uncontrolled component, form data is handled by the DOM itself, similar to traditional HTML forms. React does not manage the input state; instead, you access values using refs.
How It Works:
Form inputs maintain their own state in the DOM.
Values are accessed using
useRefordocument.getElementById.Useful for simple forms where React doesn’t need to track every change.
Example:
import { useRef } from 'react';
function UncontrolledForm() {
const nameRef = useRef(null);
const handleSubmit = (e) => {
e.preventDefault();
alert(`Submitted Name: ${nameRef.current.value}`);
};
return (
<form onSubmit={handleSubmit}>
<label>
Name:
<input type="text" ref={nameRef} />
</label>
<button type="submit">Submit</button>
</form>
);
}
Pros of Uncontrolled Components:
✅ Less boilerplate – No need for useState for every input.
✅ Better performance – No re-renders on every keystroke.
✅ Easier integration with non-React code (e.g., vanilla JS libraries).
Cons of Uncontrolled Components:
❌ Harder to validate dynamically – No real-time control over input.
❌ Less predictable – State lives in the DOM, not React.
When to Use Each Approach
| Scenario | Controlled | Uncontrolled |
| Need real-time validation | ✅ Best | ❌ Not ideal |
| Large forms with many inputs | ⚠️ Possible | ✅ Better |
| Integrating with non-React | ❌ Avoid | ✅ Best |
| Simple forms | ⚠️ Overkill | ✅ Best |
Conclusion
Use Controlled Components when you need fine-grained control over form state (e.g., dynamic validation, instant UI feedback).
Use Uncontrolled Components for simple forms, performance-critical cases, or when working with non-React libraries.
Both approaches have their place in React development. Choose based on your project’s needs!





