Skip to main content

Welcome to a Grasp lesson

Create a free account to keep studying and create your own study path.

Lesson 35

Controlled Forms with useState

Recommended resources

Hello! Welcome to your next lesson.

In our last two sessions, we built a solid understanding of the useState hook. We learned how to add state to our components and, crucially, how to update that state reliably using the functional updater pattern, especially when the new state depends on the old.

Today, we'll apply that knowledge to one of the most fundamental tasks in web development: handling user input. Our goal is to build controlled form inputs for text, select, and checkboxes using useState. This is a core skill you'll use constantly, whether building a login page, a search bar, or an e-commerce checkout.

What Are Controlled Components?

In React, the term "controlled component" refers to a form input whose value is controlled by React state. Instead of the HTML input element managing its own internal state (like what happens by default), we let our component's state be the "single source of truth."

This creates a two-way data binding loop:

  1. State to UI: The React state dictates what the input field displays.
  2. UI to State: User actions (like typing) trigger an event handler that updates the React state.

This gives us complete control over the form data at all times.

React Controlled Forms Data Flow
This diagram illustrates the cycle of a controlled component. The component's state updates the form input's value, and user changes to the input update the component's state.

Let's see how to implement this pattern.


1. The Core Pattern: Controlled Text Inputs

The most common form element is the text input. Creating a controlled text input requires two key pieces:

  1. A useState variable to hold the input's value.
  2. Binding the input's value attribute to this state variable.
  3. Using the onChange event handler to update the state with the user's input, which we get from event.target.value.

The following video provides a clear, step-by-step demonstration.

Full React Tutorial #27 - Controlled Inputs (forms)

Watch this segment from the "Full React Tutorial" by Net Ninja. It perfectly demonstrates how to set up a state variable and connect it to a text input to make it a controlled component.

Watch from 04:08 to 06:57. Pay close attention to how the value attribute and the onChange handler work together. The instructor also helpfully logs the state to the screen so you can see it update in real-time.

To summarize the pattern for a text input:

import { useState } from 'react';

function MyForm() {
  // 1. Declare a state variable to hold the input value
  const [name, setName] = useState('');

  return (
    <input
      type="text"
      // 2. Bind the input's value to the state variable
      value={name}
      // 3. Update the state when the user types
      onChange={(e) => setName(e.target.value)}
    />
  );
}

This same pattern applies directly to <textarea> elements as well, as they also use the value and onChange attributes in the same way.

For a deeper conceptual reading on this topic, the article "Data binding in React" by Josh W. Comeau is an excellent resource. You can refer to the introductory section to reinforce your understanding of controlled fields.


2. Handling Selects and Checkboxes

While other inputs follow a similar principle, there are slight but important differences in their implementation.

Select (Dropdown) Menus

A <select> element is handled almost identically to a text input. You bind the value prop on the <select> tag itself to your state variable, and the onChange handler will give you the chosen <option>'s value.

Full React Tutorial #27 - Controlled Inputs (forms)

Let's return to the Net Ninja video. The next section demonstrates how to control a <select> element.

Watch from 07:48 to 09:20. Notice that the value and onChange logic on the <select> tag is exactly the same as it was for the text input.

The pattern for a select input:

const [selection, setSelection] = useState('option1');

<select value={selection} onChange={(e) => setSelection(e.target.value)}>
  <option value="option1">Option 1</option>
  <option value="option2">Option 2</option>
</select>

Checkbox Inputs

Checkboxes are a bit different. Instead of a text value, their state is binary: checked or unchecked (a boolean).

  • Instead of the value attribute, we use the checked attribute to control its state.
  • In the onChange handler, we get the new state from event.target.checked, which will be true or false.

This video explains it clearly.

ReactJS : Working with Forms with useState Hook (radio buttons,checkboxes,dropdown menus) Part2

This video from NoobCoder focuses on different form inputs and provides a great explanation for checkboxes.

Watch from 03:04 to 05:30. Focus on how the checked attribute is used instead of value, and how the handler function uses e.target.checked to update the boolean state.

The pattern for a checkbox:

const [isChecked, setIsChecked] = useState(false);

<label>
  <input
    type="checkbox"
    // Use the `checked` attribute for checkboxes
    checked={isChecked}
    // Update state using the boolean from `e.target.checked`
    onChange={(e) => setIsChecked(e.target.checked)}
  />
  Accept terms and conditions
</label>

The Big Picture

The simple patterns you learned today are the building blocks for any form in React, no matter how complex. By combining them, you can build rich, interactive forms.

Comprehensive React Form Example with Submitted Data
This image shows a complex form with various input types. Each input here would be controlled by a piece of state using the patterns we've just discussed.

In a form with many fields like the one above, you'll often manage all the values in a single state object rather than many separate useState calls. We'll cover that more efficient pattern in an upcoming lesson on building a multi-field contact form.


Conclusion

You've now learned how to connect form inputs to React's state management system, giving you full control over user data. This is a crucial step toward building the interactive applications you're aiming for, like your e-commerce project.

Key Takeaways:

  • Controlled Components: Form inputs whose values are controlled by React state. The state is the single source of truth.
  • Text and Select Inputs: Use the value attribute to display the state and e.target.value in the onChange handler to update it.
  • Checkbox Inputs: Use the checked attribute to display the state and e.target.checked in the onChange handler to update it.
  • The Two-Way Loop: The value/checked prop sends state to the input, and the onChange prop sends user actions back to update the state.

Preview of Next Lesson:
Now that we can control the data within our form inputs, the next logical step is to do something with that data. In the next lesson, we will learn how to handle form submission, including preventing the default browser behavior.