How to Handle Form Input in React
Use controlled inputs in React when form fields should stay fully synced with component state. This makes validation, formatting, submit logic, and conditional UI much easier to manage.
What you’ll build or solve
You’ll learn how to handle form input in React with useState(), shared change handlers, and field-specific updates. You’ll also know how to scale the same pattern across multiple input types.
Learn React on Mimo
When this approach works best
This approach is the right choice when the UI needs predictable, real-time access to field values.
Common real-world scenarios include:
- Login fields
- Search inputs
- Checkout forms
- Profile editors
- Live validation
This is a bad idea when the form is tiny and simple uncontrolled inputs are intentionally preferred.
Prerequisites
You only need:
- A React component
- Basic
useState()knowledge - Basic JSX event knowledge
Step-by-step instructions
Step 1: Sync the input value with state
The core controlled-input pattern is value plus onChange.
JavaScript
import { useState } from "react";
function SearchInput() {
const [query, setQuery] = useState("");
return (
<input
type="text"
value={query}
onChange={(event) => setQuery(event.target.value)}
placeholder="Search lessons"
/>
);
}
export default SearchInput;
This keeps React as the source of truth.
Step 2: Use one handler for multiple fields
For forms, one shared handler scales better.
JavaScript
const [formData, setFormData] = useState({
email: "",
password: ""
});
Create a reusable update function.
JavaScript
function handleChange(event) {
const { name, value } = event.target;
setFormData((prev) => ({
...prev,
[name]: value
}));
}
Connect fields by name.
JavaScript
<input
name="email"
value={formData.email}
onChange={handleChange}
/>
This removes repeated state handlers.
Step 3: Handle checkboxes and other input types
Not every field uses value.
Checkboxes use checked.
JavaScript
const [isSubscribed, setIsSubscribed] = useState(false);
<input
type="checkbox"
checked={isSubscribed}
onChange={(event) => setIsSubscribed(event.target.checked)}
/>
This keeps boolean inputs predictable.
What to look for:
- Text fields use
value - Checkboxes use
checked - Shared handlers scale well
namekeys should match state- Controlled inputs simplify validation
Examples you can copy
Single search field
JavaScript
value={query}
onChange={(event) => setQuery(event.target.value)}
Shared multi-field handler
JavaScript
[event.target.name]: event.target.value
Checkbox
JavaScript
checked={isSubscribed}
Common mistakes and how to fix them
Mistake 1: Missing value
What the reader might do:
Use onChange without binding the field value.
Why it breaks: the input becomes uncontrolled.
Corrected approach:
Always pair value with onChange.
Mistake 2: Wrong name mapping
What the reader might do:
JavaScript
name="userEmail"
but state uses email.
Why it breaks: the wrong key updates.
Corrected approach:
Align name with the state property.
Mistake 3: Using value for checkboxes
What the reader might do:
JavaScript
value={isSubscribed}
Why it breaks: checkbox state should use checked.
Corrected approach:
Use checked.
Troubleshooting
If typing does not work, confirm the input has both value and onChange.
If shared updates fail, verify name matches the state key.
If checkbox state behaves oddly, switch from value to checked.
If performance drops in huge forms, consider a form library.
Quick recap
- Use controlled inputs with state
- Pair
valuewithonChange - Use shared handlers for multiple fields
- Use
checkedfor checkboxes - Keep
namealigned with state keys
Join 40M+ people learning for free on Mimo
4.8 out of 5 across 1M+ reviews
Check us out on Apple AppStore, Google Play Store, and Trustpilot