React
Forms in React
Build a search filter component for DataFlow's analytics dashboard with form inputs, validation, and user feedback.
Forms make your React apps interactive. Every search box, login screen, and settings panel needs form handling. React handles forms differently than regular HTML — forms become part of your component's state instead of just sitting in the DOM. Think about DataFlow's filter bar. Users type search terms, pick date ranges, and select categories. Each keystroke updates the interface instantly. That's React forms in action.Form Elements in JSX
HTML forms use attributes likevalue and defaultValue. JSX is similar but uses camelCase for attributes and curly braces for dynamic values.
// DataFlow search component - basic form structure
function DataFlowSearch() {
return (
<form>
<input
type="text"
placeholder="Search transactions..."
className="search-input"
/>
<select className="category-select">
<option value="">All Categories</option>
<option value="revenue">Revenue</option>
<option value="expenses">Expenses</option>
</select>
</form>
);
}What just happened?
React rendered a static form with HTML elements. But typing doesn't update any state yet — the form exists but doesn't communicate with your component. Try typing in the search box.
Handling Form Events
Forms trigger events when users interact with them. The most common areonChange for input changes and onSubmit for form submission.
// DataFlow search with event handling
function DataFlowSearch() {
function handleInputChange(event) {
console.log('User typed:', event.target.value);
}
function handleSubmit(event) {
event.preventDefault(); // Stop page reload
console.log('Form submitted!');
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
placeholder="Search transactions..."
onChange={handleInputChange}
/>
<button type="submit">Search</button>
</form>
);
}What just happened?
React captured form events and prevented the default browser behavior. The event.preventDefault() stops the page from refreshing on form submit. Try typing and clicking Search — watch the console logs appear.
event.target.value gives you the current input value. But this approach doesn't store the value anywhere in your component. React calls this "uncontrolled" because the DOM manages the input's value.
Form State with useState
Real form handling needs state to store user input. Each form field gets its own state variable, or you can use an object for multiple fields.// DataFlow search with state management
function DataFlowSearch() {
const [searchTerm, setSearchTerm] = React.useState('');
const [category, setCategory] = React.useState('');
function handleSubmit(event) {
event.preventDefault();
console.log('Searching for:', searchTerm, 'in', category);
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={searchTerm}
onChange={(e) => setSearchTerm(e.target.value)}
placeholder="Search transactions..."
/>
<select
value={category}
onChange={(e) => setCategory(e.target.value)}
>
<option value="">All Categories</option>
<option value="revenue">Revenue</option>
<option value="expenses">Expenses</option>
</select>
<button type="submit">Search</button>
</form>
);
}What just happened?
React now controls the form values through state. Each keystroke triggers a state update, which re-renders the component with the new value. Notice how the current values display in real-time below the form.
Multiple Form Fields
Real forms have many fields. You can manage them individually or group related data into a single state object. Object state works well for forms with many related fields.// DataFlow user settings form with multiple fields
function UserSettingsForm() {
const [settings, setSettings] = React.useState({
name: 'Sarah Chen',
email: 'sarah@dataflow.com',
notifications: true,
theme: 'dark'
});
function handleChange(event) {
const { name, value, type, checked } = event.target;
setSettings(prev => ({
...prev,
[name]: type === 'checkbox' ? checked : value
}));
}
return (
<form>
<input
name="name"
value={settings.name}
onChange={handleChange}
placeholder="Full Name"
/>
<input
name="email"
type="email"
value={settings.email}
onChange={handleChange}
placeholder="Email"
/>
<label>
<input
name="notifications"
type="checkbox"
checked={settings.notifications}
onChange={handleChange}
/> Email notifications
</label>
</form>
);
}What just happened?
One handleChange function manages all form fields using the input's name attribute. The spread operator ...prev keeps existing values while updating just the changed field. Try editing any field and watch the JSON update.
[name]: value syntax uses computed property names — the input's name becomes the object key. This pattern scales well as you add more form fields.
Form Validation
Production forms need validation to catch errors before submission. You can validate on every change, on blur, or just before submit. Real-time validation provides the best user experience.// DataFlow signup form with validation
function SignupForm() {
const [form, setForm] = React.useState({
email: '',
password: ''
});
const [errors, setErrors] = React.useState({});
function validateField(name, value) {
if (name === 'email') {
return value.includes('@') ? '' : 'Valid email required';
}
if (name === 'password') {
return value.length >= 8 ? '' : 'Password must be 8+ characters';
}
return '';
}
function handleChange(event) {
const { name, value } = event.target;
setForm(prev => ({ ...prev, [name]: value }));
const error = validateField(name, value);
setErrors(prev => ({ ...prev, [name]: error }));
}
return (
<form>
<input
name="email"
value={form.email}
onChange={handleChange}
placeholder="Email"
/>
{errors.email && <span style={{color: 'red'}}>{errors.email}</span>}
<input
name="password"
type="password"
value={form.password}
onChange={handleChange}
placeholder="Password"
/>
{errors.password && <span style={{color: 'red'}}>{errors.password}</span>}
</form>
);
}What just happened?
Validation runs on every keystroke, immediately showing or hiding error messages. The component manages both form data and error states separately. Try typing incomplete email addresses or short passwords to see validation in action.
Common Form Patterns
Here are patterns you'll use in every React app:Reset Forms
Set state back to initial values after successful submit.
Disable Submit
Check if form is valid or submitting to disable the submit button.
Loading States
Show spinners or change button text while processing form submission.
Field Arrays
Dynamic lists where users can add/remove items like tags or addresses.
// Complete DataFlow transaction form with common patterns
function TransactionForm() {
const [form, setForm] = React.useState({
amount: '',
description: '',
category: 'revenue'
});
const [isSubmitting, setIsSubmitting] = React.useState(false);
const isValid = form.amount && form.description;
async function handleSubmit(event) {
event.preventDefault();
if (!isValid) return;
setIsSubmitting(true);
// Simulate API call
await new Promise(resolve => setTimeout(resolve, 1000));
setIsSubmitting(false);
// Reset form after success
setForm({ amount: '', description: '', category: 'revenue' });
}
function handleChange(event) {
const { name, value } = event.target;
setForm(prev => ({ ...prev, [name]: value }));
}
return (
<form onSubmit={handleSubmit}>
<input
name="amount"
type="number"
value={form.amount}
onChange={handleChange}
placeholder="Amount ($)"
/>
<input
name="description"
value={form.description}
onChange={handleChange}
placeholder="Description"
/>
<select name="category" value={form.category} onChange={handleChange}>
<option value="revenue">Revenue</option>
<option value="expenses">Expenses</option>
</select>
<button
type="submit"
disabled={!isValid || isSubmitting}
>
{isSubmitting ? 'Adding...' : 'Add Transaction'}
</button>
</form>
);
}What just happened?
The form demonstrates professional patterns — validation disables submit, loading states prevent double-clicks, and successful submission resets the form. Fill out both required fields to enable the submit button, then watch the loading state and reset behavior.
Quiz
1. The DataFlow team needs to prevent their search form from refreshing the page when submitted. What method should they call in the submit handler?
2. What makes a form input "controlled" in React?
3. DataFlow has a checkbox for "Show advanced filters". Which prop controls whether it appears checked?
Up Next: Controlled Components
Master the difference between controlled and uncontrolled components, and learn when to use each pattern for optimal form performance.