How to Create a Form in React
Use React forms when your app needs user input, validation, submissions, or multi-step workflows. The cleanest starting point is a controlled form using useState() and an onSubmit handler.
What you’ll build or solve
You’ll learn how to create a form in React with controlled inputs, state, and submit handling. You’ll also know how to scale the pattern to multiple fields.
Learn React on Mimo
When this approach works best
This approach is the right choice when the UI needs predictable input state and easy validation.
Common real-world scenarios include:
- Login forms
- Checkout details
- Search bars
- Profile editors
- Feedback forms
This is a bad idea when the form is huge and better handled by a dedicated library like React Hook Form.
Prerequisites
You only need:
- A React component
- Basic
useState()knowledge - Basic JSX knowledge
Step-by-step instructions
Step 1: Create controlled form state
Start with one field in state.
JavaScript
import { useState } from "react";
function LoginForm() {
const [email, setEmail] = useState("");
function handleSubmit(event) {
event.preventDefault();
console.log(email);
}
return (
<form onSubmit={handleSubmit}>
<input
type="email"
value={email}
onChange={(event) => setEmail(event.target.value)}
/>
<button type="submit">Log in</button>
</form>
);
}
export default LoginForm;
This keeps the input value fully controlled by React state.
Step 2: Add multiple fields
For multiple inputs, use one state object.
JavaScript
const [formData, setFormData] = useState({
email: "",
password: ""
});
Update the changed field dynamically.
JavaScript
function handleChange(event) {
const { name, value } = event.target;
setFormData((prev) => ({
...prev,
[name]: value
}));
}
Then connect the fields.
JavaScript
<input
name="email"
value={formData.email}
onChange={handleChange}
/>
This scales well for most common forms.
Step 3: Add submit logic and validation
Basic validation fits naturally inside submit handlers.
JavaScript
function handleSubmit(event) {
event.preventDefault();
if (!formData.email) {
alert("Email is required");
return;
}
console.log(formData);
}
What to look for:
- Controlled inputs use
value+onChange - Use
event.preventDefault()on submit - Object state scales better for many fields
- Great for validation
- Keep field names aligned with state keys
Examples you can copy
Search form
JavaScript
<input
value={query}
onChange={(event) => setQuery(event.target.value)}
/>
Login form object state
JavaScript
const [formData, setFormData] = useState({
email: "",
password: ""
});
Submit handler
JavaScript
<form onSubmit={handleSubmit}>
Common mistakes and how to fix them
Mistake 1: Forgetting preventDefault()
What the reader might do:
Submit the form without blocking browser refresh.
Why it breaks: the page reloads and resets the app state.
Corrected approach:
Use event.preventDefault().
Mistake 2: Missing value on controlled inputs
What the reader might do:
Use onChange but no value.
Why it breaks: the field becomes uncontrolled or inconsistent.
Corrected approach:
Always pair both.
Mistake 3: Wrong name attributes in shared handlers
What the reader might do:
Mismatch name="userEmail" with formData.email.
Why it breaks: the wrong key updates.
Corrected approach:
Align field names with state keys.
Troubleshooting
If the page refreshes, add preventDefault().
If typing does not work, confirm value and onChange are both present.
If shared handlers fail, verify input name values.
If the form grows large, consider React Hook Form.
Quick recap
- Use controlled inputs with state
- Pair
valuewithonChange - Prevent default form refresh
- Use object state for multiple fields
- Align
nameattributes with state keys
Join 35M+ 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