React Forms
In React, form inputs are usually connected to state so your component always knows what the user typed.
Controlled Inputs
A controlled input gets its value from state and updates the state on every change.
Example
import { useState } from "react";
function NameInput() {
const [name, setName] = useState("");
return (
<div>
<input
type="text"
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Your name"
/>
<p>Hello, {name || "guest"}!</p>
</div>
);
}(typing "Ayesha") Hello, Ayesha!
The flow is: the user types, onChange runs, state updates, React re-renders, and the input shows the new value.
If you set value but forget onChange, the input becomes read-only and React warns you in the console.
Submitting a Form
Handle onSubmit on the <form> and call preventDefault() so the page does not reload.
Example
function AdmissionForm() {
const [name, setName] = useState("");
const [phone, setPhone] = useState("");
const [message, setMessage] = useState("");
function handleSubmit(e) {
e.preventDefault();
setMessage(`Thank you ${name}, we will call you on ${phone}.`);
setName("");
setPhone("");
}
return (
<form onSubmit={handleSubmit}>
<input value={name} onChange={(e) => setName(e.target.value)} placeholder="Name" />
<input value={phone} onChange={(e) => setPhone(e.target.value)} placeholder="Phone" />
<button type="submit">Apply</button>
{message && <p>{message}</p>}
</form>
);
}Thank you Bilal, we will call you on 0300-1234567.
Many Fields in One Object
For bigger forms, keep all values in one object and use the input's name to update the right field.
Example
function SignupForm() {
const [form, setForm] = useState({ email: "", course: "web", agree: false });
function handleChange(e) {
const { name, value, type, checked } = e.target;
setForm({ ...form, [name]: type === "checkbox" ? checked : value });
}
return (
<form>
<input name="email" type="email" value={form.email} onChange={handleChange} />
<select name="course" value={form.course} onChange={handleChange}>
<option value="web">Web Development</option>
<option value="graphics">Graphic Designing</option>
<option value="ai">Artificial Intelligence</option>
</select>
<label>
<input name="agree" type="checkbox" checked={form.agree} onChange={handleChange} />
I agree to the rules
</label>
<p>{form.email} wants to join {form.course}</p>
</form>
);
}[name]: value is a computed property name. It uses the value of name (like "email") as the key.
Input Types at a Glance
| Field | Value prop | Read in onChange |
|---|---|---|
| Text, email, password, number | value | e.target.value |
| Textarea | value | e.target.value |
| Select | value on <select> | e.target.value |
| Checkbox | checked | e.target.checked |
| Radio | checked={choice === "x"} | e.target.value |
In React, <textarea> and <select> use a value prop, not content or a selected attribute.
Note that e.target.value is always a string, even for type="number". Use Number(e.target.value) when you need a number.
Simple Validation
Check the values before accepting them and show a message:
Example
function AgeForm() {
const [age, setAge] = useState("");
const [error, setError] = useState("");
function handleSubmit(e) {
e.preventDefault();
if (Number(age) < 16) {
setError("You must be at least 16 to enrol.");
} else {
setError("");
alert("Enrolled!");
}
}
return (
<form onSubmit={handleSubmit}>
<input type="number" value={age} onChange={(e) => setAge(e.target.value)} />
<button>Enrol</button>
{error && <p style={{ color: "red" }}>{error}</p>}
</form>
);
}Always validate again on the server too. Browser checks are only for a better user experience.
Exercise
Exercise
Which prop holds the true/false value of a controlled checkbox?
