Controlled Inputs
Bind form inputs to state so React is the single source of truth.
Syntax
<input value={text} onChange={e => setText(e.target.value)} />A controlled input gets its value from state and updates that state on every change. React drives the input, so the state always reflects exactly what the user sees.
The pattern
- Store the field in state with
useState. - Set the input's
valueto that state. - Update state in
onChangeusinge.target.value.
Example
import { useState } from 'react';
function NameField() {
const [name, setName] = useState('');
return (
<div>
<input
value={name}
onChange={(e) => setName(e.target.value)}
placeholder="Your name"
/>
<p>Hello, {name || 'stranger'}!</p>
</div>
);
}When to use it
- A registration form binds each text field to a state variable so instant validation feedback appears as the user types rather than only on submit.
- A settings panel uses controlled inputs so a Reset button can restore all fields to their default values by resetting state to the original config object.
- A rich text editor mirrors its textarea value to state so an autosave effect can access the latest content without querying the DOM.
More examples
Controlled text input
Binds the input value to state and updates state on every keystroke, making React the single source of truth.
import { useState } from 'react';
function NameInput() {
const [name, setName] = useState('');
return (
<div>
<input
value={name}
onChange={e => setName(e.target.value)}
placeholder="Your name"
/>
<p>Hello, {name || 'stranger'}!</p>
</div>
);
}Controlled select element
Applies the controlled pattern to a select element, with the current selection stored in state.
import { useState } from 'react';
function CountryPicker() {
const [country, setCountry] = useState('us');
return (
<select value={country} onChange={e => setCountry(e.target.value)}>
<option value="us">United States</option>
<option value="gb">United Kingdom</option>
<option value="de">Germany</option>
</select>
);
}Controlled form with submit
Combines multiple controlled inputs with an onSubmit handler that calls preventDefault to stop the native form POST.
import { useState } from 'react';
function LoginForm() {
const [email, setEmail] = useState('');
const [password, setPassword] = useState('');
function handleSubmit(e) {
e.preventDefault();
console.log('Submitting:', email);
}
return (
<form onSubmit={handleSubmit}>
<input value={email} onChange={e => setEmail(e.target.value)} type="email" />
<input value={password} onChange={e => setPassword(e.target.value)} type="password" />
<button type="submit">Login</button>
</form>
);
}
Discussion