Frontend Master

JavaScript Curriculum

Forms in React
+60 XP

Forms in React

medium
~30 min·60 XP

The coffee shop order form needs name, email, size selection, shot count, milk toggle, and a notes field. Every field is controlled — React owns the values, validation runs live, and submit serialises state directly.

Forms in React

React forms are controlled — state owns the value, onChange keeps it in sync. This gives you live validation, conditional fields, and easy form serialisation without touching the DOM directly.

Every Input Type — Controlled

Text, select, checkbox, radio, textarea — each one controlled:

controlled-inputs.jsx

The value is always in sync with state. React drives the input — the DOM follows.

const [value, setValue] = useState('')

<input
  type="text"
  value={value}
  onChange={e => setValue(e.target.value)}
  placeholder="Type here..."
/>
Live input
State value
""
ℹ️The controlled input contract
A controlled input has two required props: `value` (or `checked`) and `onChange`. Miss either one and React warns you. `value` without `onChange` makes the input read-only. `onChange` without `value` makes it uncontrolled.

Full Order Form — All Input Types Together

A real form with live state, validation on blur, and submit handling:

order-form.jsx
Live form state
{
  "name": "",
  "email": "",
  "size": "medium",
  "extras": [],
  "notes": "",
  "newsletter": false
}
💡One handleChange for all fields
Give every input a `name` attribute that matches its state key. Then: `const handleChange = (e) => setForm(prev => ({ ...prev, [e.target.name]: e.target.type === 'checkbox' ? e.target.checked : e.target.value }))`. One function handles text, select, textarea, and checkbox.

Controlled vs Uncontrolled — Know the Difference

When to use each approach:

controlled-vs-uncontrolled.jsx
const [value, setValue] = useState('')

<input
  value={value}
  onChange={e => setValue(e.target.value)}
/>
Live state: ""
Comparison
Data stored inReact stateDOM (ref.current.value)
Source of truthuseState / useReducerDOM element itself
Real-time access✓ Always — it's state✗ Only on demand (read ref)
Live validation✓ On every keystroke✗ Only on submit
Conditional disable✓ Based on state✗ Harder to implement
Reset formsetForm(initialValues)form.reset()
BoilerplateMore — handler per fieldLess — just a ref
Use whenMost cases — forms with validation, dynamic fieldsSimple forms, file inputs, third-party integrations
⚠️Almost always use controlled inputs
Uncontrolled inputs are only appropriate for file inputs (which cannot be controlled), third-party library integration (e.g., a rich text editor), and performance-critical forms with hundreds of fields. In all other cases, controlled inputs are the React way.

Your Challenge

Build a controlled coffee order form: name (text), email (text with @ validation), size (select: small/medium/large), shots (radio: 1/2/3), milk (checkbox), notes (textarea). Single handleChange. Validate name + email on blur with error messages. On submit: e.preventDefault(), validate all, show JSON summary if valid.

Challenge

Build a fully controlled order form with: text inputs (name, email), select (size), radio group (shots: 1/2/3), checkbox (milk), textarea (notes). One handleChange handles all fields. Validate name and email on blur and on submit. Show a success message with the submitted data.

controlled-inputonChangeonSubmite.target.valuee.target.checkedselectcheckboxradiotextareaform-validationuncontrolleduseRefdefaultValue
Forms in React | Nexus Learn