Forms in React
Controlled inputs, form state, validation, and submission
Free tier: read the explanation here. Upgrade to Pro for Drills, Speed challenges & Mastery badges.
UpgradeKnowledge Debt detected
You can study this freely — but your score may plateau if these foundations have gaps. The Mastery badge requires them to be solid.
Explanation
React forms use s — the form field value is driven by React state.
function SignupForm() {
const [form, setForm] = useState({ email: '', password: '' });
const [error, setError] = useState('');
const handleChange = (e) => {
const { name, value } = e.target;
setForm(prev => ({ ...prev, [name]: value }));
};
const handleSubmit = (e) => {
e.preventDefault();
if (!form.email.includes('@')) {
setError('Invalid email');
return;
}
// submit logic
};
return (
<form onSubmit={handleSubmit}>
<input name="email" value={form.email} onChange={handleChange} />
<input name="password" type="password" value={form.password} onChange={handleChange} />
{error && <p className="error">{error}</p>}
<button type="submit">Sign Up</button>
</form>
);
}Why controlled inputs:
- React is the single source of truth
- You can validate on every keystroke
- Easy to programmatically clear or prefill
Checkbox and select:
jsx // Checkbox <input type="checkbox" checked={agree} onChange={e => setAgree(e.target.checked)} /> // Select <select value={role} onChange={e => setRole(e.target.value)}> <option value="user">User</option> <option value="admin">Admin</option> </select>
Uncontrolled inputs with ref exist but are less common in React.
Examples
Generic handleChange for any field
One generic handler for all inputs using computed property names
const [form, setForm] = useState({ name: '', email: '', role: 'user' });
const handleChange = ({ target: { name, value, type, checked } }) => {
setForm(prev => ({
...prev,
[name]: type === 'checkbox' ? checked : value,
}));
};
// All inputs use the same handler — just set name= correctly
<input name="name" value={form.name} onChange={handleChange} />
<input name="email" value={form.email} onChange={handleChange} />Real-time validation
Validate on every keystroke using derived state
function EmailInput() {
const [email, setEmail] = useState('');
const isValid = email === '' || email.includes('@');
return (
<div>
<input
type="email"
value={email}
onChange={e => setEmail(e.target.value)}
className={isValid ? '' : 'input-error'}
/>
{!isValid && <span className="error-text">Enter a valid email</span>}
</div>
);
}How well did you understand this?
Next in React
Lifting State Up