Learn the concept
Forms
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:
React 19 Form Actions:
<form action={fn}> — pass a function directly to form's action propuseActionState — tracks form state (pending, error, result)useFormStatus — access pending state from form childrenfunction 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>
);
}Controlled input with debounced API calls for autocomplete/search-as-you-type
Uncontrolled file inputs combined with controlled metadata fields in upload forms
Controlled forms where field types, validation rules, and layout are driven by configuration
Build a checkout form with controlled inputs, validation, address autocomplete, and payment fields
Create a drag-and-drop form builder that generates controlled/uncontrolled forms from JSON schema