← Back to React Course | Chapter 4: State & Event Handling | Lesson 6 of 10

Controlled Input Basics

A controlled input is a text box that always shows exactly what React tells it to show, instead of managing its own memory.

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

markup
<!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

markup
<!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

markup
<!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>
Common Mistakes
  1. Setting an input's value from state without also providing an onChange handler, which makes the field impossible to type into.
  2. Mixing controlled and uncontrolled patterns on the same input (e.g. setting value but never updating state on change).
  3. Forgetting value={undefined} on first render causes a 'switching from uncontrolled to controlled' warning later.
Chapter Summary
  • A controlled input's value is driven entirely by React state.
  • The value prop and onChange handler 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.
Browser Support

No browser-specific restrictions -- controlled inputs are a React pattern layered on top of standard HTML form elements.

Login to run this code

C/C++/Java/PHP execution requires a free account. Your code is saved — you'll land right back in the editor after logging in.