Forms & Controlled Inputs 📝
Controlled inputs are like smart whiteboards: React keeps an authoritative copy of the text, ensuring UI and state never drift apart.
Controlled Basics ✍️
'use client';
import { useState } from 'react';
export function NewsletterForm() {
const [email, setEmail] = useState('');
const handleSubmit = (evt: React.FormEvent) => {
evt.preventDefault();
subscribe(email);
};
return (
<form onSubmit={handleSubmit}>
<label>
Email
<input value={email} onChange={e => setEmail(e.target.value)} />
</label>
<button disabled={!email.includes('@')}>Join</button>
</form>
);
}- The
valueprop reflects state;onChangeupdates state. - Keeps validation, formatting, and UI feedback centralized.
Multiple Fields 🌱
const [form, setForm] = useState({ name: '', role: 'dev' });
const handleChange = (evt: React.ChangeEvent<HTMLInputElement | HTMLSelectElement>) => {
const { name, value } = evt.target;
setForm(prev => ({ ...prev, [name]: value }));
};- Use
nameattributes to update arbitrary fields. - Consider
useReducerfor complex forms.
Server Actions & Forms ⚙️
- In Next.js App Router, forms can call server actions via
action={async formData => ...}. - Validate both client-side (UX) and server-side (security).
Controlled vs Uncontrolled ⚖️
- Controlled: React state is the source of truth (most predictable).
- Uncontrolled: rely on DOM state + refs (
defaultValue,ref.current.value). Useful for simple forms or performance-sensitive inputs.
UX Tips 💡
- Debounce expensive operations triggered on
onChange(e.g., search suggestions). - Use
useRefto manage focus/selection after submit. - Provide inline validation messages synchronized with state.
Analogy: controlled inputs are shared Google Docs—everyone edits the same canonical version, so there are no conflicting copies.
Mastering them makes integrating Next.js server features (actions, mutations) smooth and predictable. ✅
Last updated on