Checkboxes, selects, and textareas
Real forms are more than text boxes: a signup page has a plan dropdown, a newsletter checkbox, a bio field. In plain HTML each control reports its value differently, which is exactly the inconsistency React's controlled pattern smooths over. Every control becomes the same loop from lesson 6-1, state in, onChange out, with two adjustments worth knowing before your first real form.
Textareas take value, not children. In HTML the text sits between the tags: <textarea>hello</textarea>. JSX moves it to the value prop so a textarea is controlled exactly like an input, one consistent pattern instead of a special case:
<textarea value={bio} onChange={e => setBio(e.target.value)} />Selects take value on the <select>, not selected on an option. HTML marks the chosen <option> with a selected attribute, scattering the answer across the children. React centralizes it, the select's value prop decides which option shows, so the current choice lives in one place: your state.
<select value={plan} onChange={e => setPlan(e.target.value)}>
<option value="free">Free</option>
<option value="pro">Pro</option>
</select>Checkboxes: checked, not value
A checkbox's value attribute is a constant label that never changes when you click, the fact that does change is the boolean checked. So a controlled checkbox pairs checked with e.target.checked:
<input type="checkbox" checked={newsletter} onChange={e => setNewsletter(e.target.checked)} />
With several mixed controls, one generic handler beats a handler per field. Give each control a name attribute matching its field in the form object, then branch on the control type, this is the multi-field spread pattern from lesson 6-2, generalized:
function handleChange(e) { const value = e.target.type === "checkbox" ? e.target.checked : e.target.value; setForm({ ...form, [e.target.name]: value }); }
One function now serves the dropdown, the checkbox, and the textarea. This exact helper appears in countless production codebases.
Code exercise · javascript
Your turn. Complete handleChange(form, target): read target.checked when target.type is "checkbox", otherwise target.value, and return a new form object with only target.name updated (spread + computed property name, lesson 6-2). The three simulated events fill a plan select, a newsletter checkbox, and a bio textarea.
Quiz
Spot the bug: ```jsx const [agreed, setAgreed] = useState(false); return <input type="checkbox" value={agreed} onChange={e => setAgreed(e.target.value)} />; ```
Quiz
Where does React put the current choice of a controlled dropdown?