A controlled input’s value comes from React state. Every keystroke fires onChange, updates state, and re-renders with the new value. React is the source of truth—not the DOM.
Text input pattern
const [email, setEmail] = useState('');
<input value={email} onChange={(e) => setEmail(e.target.value)} />
Checkboxes and selects
- Checkbox:
checked={agreed}+onChangereadinge.target.checked - Select:
value={role}on<select>with matching<option value>
Important interview questions and answers
- Q: Controlled vs uncontrolled?
A: Controlled ties value to state; uncontrolled reads from refs/DOM—controlled is default in React apps for forms you validate. - Q: Why might input feel laggy?
A: Expensive re-renders on every keystroke—optimize child components or debounce validation, not the controlled pattern itself.
Self-check
- What breaks if you forget
valuebut keeponChange? - How do you read checkbox state in an event handler?
Challenge
Live echo
- Type in the input and confirm the paragraph mirrors text.
- Add a max length of 20 characters via
maxLength.
Done when: the echo updates on every keystroke and stops at 20 characters.
Challenge
Single source of truth
- Log the state value on every keystroke with
printOutput. - Confirm the input never stores its own shadow copy.
Done when: terminal reflects the same string shown in the input.