Form handling in React revolves around two distinct patterns for input data management: Controlled Components (where React state acts as the single source of truth) and Uncontrolled Components (where the DOM retains internal form state accessed via React useRef).
flowchart LR
subgraph Controlled ["Controlled Pattern"]
A["Input Change Event"] --> B["React useState State Update"]
B --> C["Input value={state}"]
end
subgraph Uncontrolled ["Uncontrolled Pattern"]
D["Input Change Event"] --> E["Native DOM State"]
E --> F["Read value via ref.current.value"]
end
import React, { useState } from 'react';
export default function RegistrationForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
subscribeNewsletter: false,
});
const handleChange = (e) => {
const { name, value, type, checked } = e.target;
setFormData((prev) => ({
...prev,
[name]: type === 'checkbox' ? checked : value,
}));
};
const handleSubmit = (e) => {
e.preventDefault();
console.log('Submitted Payload:', formData);
};
return (
<form onSubmit={handleSubmit} className="form-card">
<h2>Register Account</h2>
<label>
Username:
<input
type="text"
name="username"
value={formData.username}
onChange={handleChange}
required
/>
</label>
<label>
Email:
<input
type="email"
name="email"
value={formData.email}
onChange={handleChange}
required
/>
</label>
<label className="checkbox-label">
<input
type="checkbox"
name="subscribeNewsletter"
checked={formData.subscribeNewsletter}
onChange={handleChange}
/>
Subscribe to updates
</label>
<button type="submit">Complete Sign Up</button>
</form>
);
}
| Feature | Controlled Component | Uncontrolled Component |
|---|---|---|
| State Storage | React useState |
Browser HTML DOM |
| Value Access | Always available in state variable | Read using inputRef.current.value |
| Validation | Real-time instant validation per keystroke | Validation on form submit |
| Best Used For | Dynamic forms, conditional inputs, instant UX feedback | Simple forms, file inputs (<input type="file" />) |
<input type="file" /> is read-only in the DOM for security reasons. Always manage file inputs using useRef().undefined Warnings: If value evaluates to undefined on initial render, React flags the input as uncontrolled. Always initialize form state with empty strings ('') or non-null defaults.Build a controlled input field that live-validates password length and turns the border red if the password is fewer than 8 characters long.
Sign in to track your learning journey, earn industry-recognized certificates, and join our elite developer community.
Quick Access With