Controlled components have their form data managed by React state - the input value is always driven by state. Uncontrolled components let the DOM handle form data using refs to access values when needed. Controlled components are recommended for most cases.
Controlled Components:
Uncontrolled Components:
When to Use Each:
function ControlledForm() {
const [formData, setFormData] = useState({
name: '',
email: '',
agree: false
});
const [errors, setErrors] = useState({});
const handleChange = (e) => {
const { name, value, type, checked } = e.target;
setFormData(prev => ({
...prev,
[name]: type === 'checkbox' ? checked : value
}));
};
const validate = () => {
const newErrors = {};
if (!formData.name) newErrors.name = 'Name required';
if (!formData.email.includes('@')) newErrors.email = 'Invalid email';
setErrors(newErrors);
return Object.keys(newErrors).length === 0;
};
const handleSubmit = (e) => {
e.preventDefault();
if (validate()) {
console.log('Submit:', formData);
}
};
return (
<form onSubmit={handleSubmit}>
<input
name="name"
value={formData.name}
onChange={handleChange}
/>
{errors.name && <span>{errors.name}</span>}
<input
name="email"
value={formData.email}
onChange={handleChange}
/>
<input
type="checkbox"
name="agree"
checked={formData.agree}
onChange={handleChange}
/>
<button disabled={!formData.agree}>Submit</button>
</form>
);
}