Controlled Input Basics
In this page:
Making an Input Controlled
An input becomes controlled when its value comes from React state and its onChange handler updates that same state. This creates a loop where React fully owns what the input displays at every moment, rather than the browser managing it independently.
Note: Always pair a controlled input's value prop with an onChange handler -- one without the other causes problems.
Warning: An input with only value set and no onChange becomes read-only and logs a console warning.
Example: Making an Input Controlled
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function NameField() {
const [name, setName] = React.useState("");
return (
<input
value={name}
onChange={(e) => setName(e.target.value)}
/>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<NameField />);
</script>
</body>
</html>
Reading the Controlled Value Elsewhere
Because a controlled input's value lives in state, it's trivial to use that same value anywhere else in the component, like showing a live preview as the user types. This immediate reactivity is one of the main benefits of the controlled pattern.
Note: Controlled inputs make instant validation feedback (like showing a character count) easy since the value is always available in state.
Warning: If you forget to update state in the onChange handler, the field will appear stuck and not respond to typing at all.
Example: Reading the Controlled Value Elsewhere
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function LivePreview() {
const [text, setText] = React.useState("");
return (
<div>
<input value={text} onChange={(e) => setText(e.target.value)} />
<p>Preview: {text}</p>
</div>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<LivePreview />);
</script>
</body>
</html>
Controlled Checkboxes and Selects
The controlled pattern extends beyond text inputs to checkboxes (using the checked prop instead of value) and select dropdowns (using value on the <select> itself). Each form element type has its own small variation on the same controlled idea.
Note: Checkboxes use checked/onChange with event.target.checked, not value/event.target.value.
Warning: Using value instead of checked on a controlled checkbox doesn't work -- checkboxes need the boolean checked prop specifically.
Example: Controlled Checkboxes and Selects
<!DOCTYPE html>
<html>
<head>
<script src="https://unpkg.com/react@18/umd/react.development.js"></script>
<script src="https://unpkg.com/react-dom@18/umd/react-dom.development.js"></script>
<script src="https://unpkg.com/@babel/standalone/babel.min.js"></script>
</head>
<body>
<div id="root"></div>
<script type="text/babel">
function Preferences() {
const [subscribed, setSubscribed] = React.useState(false);
return (
<label>
<input
type="checkbox"
checked={subscribed}
onChange={(e) => setSubscribed(e.target.checked)}
/>
Subscribe: {subscribed ? "Yes" : "No"}
</label>
);
}
ReactDOM.createRoot(document.getElementById('root')).render(<Preferences />);
</script>
</body>
</html>
- Setting an input's
valuefrom state without also providing anonChangehandler, which makes the field impossible to type into. - Mixing controlled and uncontrolled patterns on the same input (e.g. setting
valuebut never updating state on change). - Forgetting
value={undefined}on first render causes a 'switching from uncontrolled to controlled' warning later.
- A controlled input's value is driven entirely by React state.
- The
valueprop andonChangehandler work together to keep the input and state in sync. - Controlled inputs make it easy to validate, transform, or react to input changes instantly.
- This is the standard, recommended way to handle form inputs in React.
No browser-specific restrictions -- controlled inputs are a React pattern layered on top of standard HTML form elements.
Chapter Quiz — Complete all 10 topics to unlock
0/10 topics done
Complete these topics first: