Chapter 9 of 12
Forms in React are controlled through state — unlike regular HTML forms where the DOM manages input values, React forms keep the values in state and sync the DOM to that state.
import { useState } from "react";
function ContactForm() {
const [form, setForm] = useState({
name: "",
email: "",
message: "",
course: "html",
});
const [status, setStatus] = useState("idle"); // idle | loading | success | error
// Generic handler — works for any field
function handleChange(e) {
const { name, value } = e.target;
setForm(prev => ({ ...prev, [name]: value }));
}
async function handleSubmit(e) {
e.preventDefault();
setStatus("loading");
try {
const res = await fetch("/api/contact", {
method: "POST",
headers: { "Content-Type": "application/json" },
body: JSON.stringify(form),
});
if (!res.ok) throw new Error("Failed");
setStatus("success");
setForm({ name: "", email: "", message: "", course: "html" });
} catch {
setStatus("error");
}
}
return (
<form onSubmit={handleSubmit}>
<input
name="name"
value={form.name}
onChange={handleChange}
placeholder="Your name"
required
/>
<input
name="email"
type="email"
value={form.email}
onChange={handleChange}
required
/>
<select name="course" value={form.course} onChange={handleChange}>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="js">JavaScript</option>
</select>
<textarea
name="message"
value={form.message}
onChange={handleChange}
rows={4}
/>
<button type="submit" disabled={status === "loading"}>
{status === "loading" ? "Sending..." : "Send"}
</button>
{status === "success" && <p>Message sent!</p>}
{status === "error" && <p>Something went wrong.</p>}
</form>
);
}