Forms
Forms in React work differently than in plain HTML. Instead of letting the DOM manage form state, React components control the input values using state.Controlled Components
A controlled component is an input whose value is controlled by React state:Why controlled components?
- React state is the single source of truth
- Easy to modify or validate input
- Consistent behavior across all inputs
- Simple to implement conditional logic
Handling Different Input Types
Text Inputs
Checkboxes
Radio Buttons
Select Dropdowns
Form Submission
Handle form submission withonSubmit:
Managing Multiple Inputs
Use a single change handler for multiple inputs:Form Validation
import { useState } from 'react';
function ValidatedForm() {
const [formData, setFormData] = useState({
username: '',
email: '',
password: '',
confirmPassword: ''
});
const [errors, setErrors] = useState({});
const validate = () => {
const newErrors = {};
// Username validation
if (!formData.username) {
newErrors.username = 'Username is required';
} else if (formData.username.length < 3) {
newErrors.username = 'Username must be at least 3 characters';
}
// Email validation
if (!formData.email) {
newErrors.email = 'Email is required';
} else if (!/\S+@\S+\.\S+/.test(formData.email)) {
newErrors.email = 'Email is invalid';
}
// Password validation
if (!formData.password) {
newErrors.password = 'Password is required';
} else if (formData.password.length < 8) {
newErrors.password = 'Password must be at least 8 characters';
}
// Confirm password
if (formData.password !== formData.confirmPassword) {
newErrors.confirmPassword = 'Passwords do not match';
}
return newErrors;
};
const handleSubmit = (e) => {
e.preventDefault();
const newErrors = validate();
if (Object.keys(newErrors).length === 0) {
// Form is valid
console.log('Form submitted:', formData);
setErrors({});
} else {
// Form has errors
setErrors(newErrors);
}
};
const handleChange = (e) => {
const { name, value } = e.target;
setFormData({ ...formData, [name]: value });
// Clear error when user starts typing
if (errors[name]) {
setErrors({ ...errors, [name]: '' });
}
};
return (
<form onSubmit={handleSubmit}>
<div>
<input
name="username"
value={formData.username}
onChange={handleChange}
placeholder="Username"
/>
{errors.username && <span className="error">{errors.username}</span>}
</div>
<div>
<input
name="email"
type="email"
value={formData.email}
onChange={handleChange}
placeholder="Email"
/>
{errors.email && <span className="error">{errors.email}</span>}
</div>
<div>
<input
name="password"
type="password"
value={formData.password}
onChange={handleChange}
placeholder="Password"
/>
{errors.password && <span className="error">{errors.password}</span>}
</div>
<div>
<input
name="confirmPassword"
type="password"
value={formData.confirmPassword}
onChange={handleChange}
placeholder="Confirm Password"
/>
{errors.confirmPassword && (
<span className="error">{errors.confirmPassword}</span>
)}
</div>
<button type="submit">Register</button>
</form>
);
}
Validation strategies:
- Validate on submit (less intrusive)
- Validate on blur (immediate feedback)
- Validate on change (real-time feedback)
- Combine strategies for best UX
Real-time Validation
Validate fields as the user types:Complete Contact Form Example
Best Practices
Form best practices:
- Always use controlled components for predictable behavior
- Prevent default form submission with
e.preventDefault() - Validate on both client and server side
- Provide clear, immediate error feedback
- Disable submit button during submission
- Clear errors when user corrects input
- Use semantic HTML (labels, fieldsets, etc.)
- Make forms accessible (ARIA labels, keyboard navigation)
Next Steps
You now have a solid foundation in React forms! Explore more advanced topics:- State management - Use Context API or Redux for complex form state
- Form libraries - Try Formik or React Hook Form for advanced features
- Server validation - Implement server-side validation and error handling
- File uploads - Handle file inputs and multipart form data