Multiple Inputs, Checkboxes & Selects
Manage a whole form’s worth of fields neatly with a single state object.
What you will learn
- Manage many fields with one state object
- Handle checkboxes and selects
- Update nested state with spread
One state object for the whole form
Instead of separate state for each field, hold the form in one object and update it with the spread operator.
function App() {
const [form, setForm] = useState({ name: "", course: "html", agree: false });
function update(e) {
const { name, value, type, checked } = e.target;
setForm({ ...form, [name]: type === "checkbox" ? checked : value });
}
return (
<form>
<input name="name" value={form.name} onChange={update} placeholder="Name" /><br/><br/>
<select name="course" value={form.course} onChange={update}>
<option value="html">HTML</option>
<option value="react">React</option>
</select><br/><br/>
<label><input name="agree" type="checkbox" checked={form.agree} onChange={update} /> I agree</label>
<pre>{JSON.stringify(form, null, 2)}</pre>
</form>
);
}Instead of one state per field, the whole form lives in one object: { name, course, agree }. Every input shares the same update handler. Inside it, e.target tells us which input fired and its name, value, type and checked. We build a new object with { ...form, [name]: ... }: spread copies all current fields, then [name] overwrites just the one that changed. For a checkbox we save checked (true/false); for everything else we save value. The <pre> at the bottom prints the live state so you can watch it change.
Here is exactly what happens, step by step, when you change any field:
- One object holds the whole form:
const [form, setForm] = useState({ name: "", course: "html", agree: false })— one piece of state for every field. - Each input is wired to that object: it reads its value from state (
value={form.name},checked={form.agree}) and points itsonChangeat the same sharedupdatefunction. Each input also has anameattribute ("name","course","agree") that says which field it controls. - On any change,
updateruns. It readsconst { name, value, type, checked } = e.targetto learn which input fired (name), what was typed or picked (value), and — for a checkbox — whether it is ticked (checked). - It builds a brand-new object:
setForm({ ...form, [name]: type === "checkbox" ? checked : value }). The spread...formcopies every current field, and the computed key[name]overwrites just the one that changed — savingcheckedfor a checkbox, orvaluefor a text box or dropdown. - React re-renders, so the matching input and the live
<pre>readout both update instantly.
Note: Output: A name box, a course dropdown, an “I agree” checkbox, and below them the live form object, e.g.: { "name": "Asha", "course": "react", "agree": true } Editing any field updates the matching line instantly.
Tip: The trick is the computed property name [name]: value — it uses each input’s name attribute as the object key, so one handler updates any field.
Q. What does { ...form, [name]: value } do?
✍️ Practice
- Build a form with three fields managed by one state object.
- Add a checkbox and a select to the same single-object form.
🏠 Homework
- Build a registration form (name, email, course select, terms checkbox) using one state object.