React Lesson 10: Forms in React
Forms in React are “controlled” — React state owns the form data. This gives you full control over validation, submission, and form state.
Controlled Input
import { useState } from "react";
function SignupForm() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const handleSubmit = (e) => {
e.preventDefault();
console.log("Email:", email);
console.log("Password:", password);
};
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(e) => setEmail(e.target.value)}
placeholder="Email"
/>
<input
type="password"
value={password}
onChange={(e) => setPassword(e.target.value)}
placeholder="Password"
/>
<button type="submit">Sign Up</button>
</form>
);
}
Single State Object for Multiple Fields
function ContactForm() {
const [form, setForm] = useState({
name: "",
email: "",
message: ""
});
const handleChange = (e) => {
const { name, value } = e.target;
setForm(prev => ({ ...prev, [name]: value }));
};
return (
<form>
<input name="name" value={form.name} onChange={handleChange} />
<input name="email" value={form.email} onChange={handleChange} />
<textarea name="message" value={form.message} onChange={handleChange} />
</form>
);
}
Validation
const [errors, setErrors] = useState({});
const validate = () => {
const newErrors = {};
if (!form.name.trim()) newErrors.name = "Name is required";
if (!form.email.includes("@")) newErrors.email = "Invalid email";
if (form.password.length < 8) newErrors.password = "Min 8 characters";
setErrors(newErrors);
return Object.keys(newErrors).length === 0; // true if no errors
};
const handleSubmit = (e) => {
e.preventDefault();
if (validate()) {
// submit the form
}
};
🏋️ Practice Task
Build a full registration form with: name, email, password, confirm password fields. Add validation: name required, valid email, password 8+ chars, passwords must match. Show error messages under each field. Show “Form submitted!” on success.
💡 Hint: Use separate error state. Validate on submit. Show {errors.name &&
{errors.name}
} after each input.