Popular Searches
Popular Course Categories
Popular Courses

Controlled Components

Controlled Components

React Forms

Controlled Components in React JS

Controlled Components in React JS are form elements whose values are controlled by React state. They allow developers to manage user input, validate data, update fields dynamically, and handle form submissions efficiently. Controlled components commonly use the useState Hook, the value or checked prop, and event handlers such as onChange.

Course Link: JustAcademy React JS Training Course

Demo Link: Register for React JS Course Demo


1. Learning Objectives

After completing these notes, you will be able to:

  • Understand the concept of controlled components.
  • Learn how React state controls form input values.
  • Use useState to manage user input.
  • Handle text inputs, checkboxes, radio buttons, dropdowns, and textareas.
  • Manage multiple form fields using a single state object.
  • Validate input values and display error messages.
  • Handle form submission and reset form fields.
  • Understand the difference between controlled and uncontrolled components.
  • Build a complete controlled registration form.

2. What Are Controlled Components?

A controlled component is a form element whose current value is managed by React state. The state determines what appears in the input, and an event handler updates the state when the user changes the input.

For example, when a user types their name into a controlled input, the onChange handler updates the state. React then renders the input using the updated state value.

Basic Example

import { useState } from "react";
function NameForm() {
  const [name, setName] = useState("");
  return (
    <div>
      <label htmlFor="name">Enter Your Name:</label>
      <input
        id="name"
        type="text"
        value={name}
        onChange={(event) => setName(event.target.value)}
      />
      <p>Your Name: {name}</p>
    </div>
  );
}
export default NameForm;

How It Works

  1. useState("") initializes the name state with an empty string.
  2. value={name} makes React state control the input value.
  3. onChange runs when the user edits the input.
  4. event.target.value reads the latest text entered by the user.
  5. setName() updates the state.
  6. React re-renders the component with the updated value.

3. How Controlled Components Work

Controlled components follow a simple cycle: React state provides the current value, the user changes the input, the event handler updates the state, and React renders the new value.

Controlled Component Flow

React State
    ↓
Input Receives Value
    ↓
User Changes Input
    ↓
onChange Event Runs
    ↓
State Updates
    ↓
React Re-renders Input

This approach makes React state the source of truth for the current input value.


4. Important Properties and Events

Property/Event Purpose Example
useState Stores the current input value. useState("")
value Controls the value of text inputs, textareas, and dropdowns. value={name}
checked Controls whether a checkbox or radio button is selected. checked={accepted}
onChange Handles user changes and updates state. onChange={handleChange}
event.target.value Reads the current value of most input elements. event.target.value
event.target.checked Reads the selected state of a checkbox or radio input. event.target.checked
onSubmit Handles form submission. onSubmit={handleSubmit}
preventDefault() Prevents the browser's default submission behavior. event.preventDefault()

5. Controlled Text Input

A controlled text input uses a state variable and the value prop to manage the text entered by a user.

import { useState } from "react";
function TextInput() {
  const [username, setUsername] = useState("");
  return (
    <div>
      <label htmlFor="username">Username:</label>
      <input
        id="username"
        type="text"
        value={username}
        onChange={(event) => setUsername(event.target.value)}
      />
      <p>Username: {username}</p>
    </div>
  );
}
export default TextInput;

Explanation: The input always displays the value stored in username. When the user types, setUsername() updates the state and React displays the updated text.


6. Controlled Email Input

Controlled email inputs are useful for registration forms, login pages, contact forms, and newsletter subscriptions.

import { useState } from "react";
function EmailForm() {
  const [email, setEmail] = useState("");
  return (
    <form>
      <label htmlFor="email">Email Address:</label>
      <input
        id="email"
        type="email"
        value={email}
        onChange={(event) => setEmail(event.target.value)}
      />
      <p>Entered Email: {email}</p>
    </form>
  );
}
export default EmailForm;

The type="email" attribute provides an appropriate input type and browser validation behavior. If your application needs custom validation, you can validate the state value as well.


7. Controlled Password Input

A controlled password input stores the entered password in React state. The browser masks the displayed characters because the input type is set to password.

import { useState } from "react";
function PasswordForm() {
  const [password, setPassword] = useState("");
  return (
    <div>
      <label htmlFor="password">Password:</label>
      <input
        id="password"
        type="password"
        value={password}
        onChange={(event) => setPassword(event.target.value)}
      />
      <p>Password Length: {password.length}</p>
    </div>
  );
}
export default PasswordForm;

Security note: Do not display, log, or unnecessarily store passwords. Real authentication should be handled securely by a backend.


8. Controlled Textarea

The textarea element collects longer text such as feedback, comments, descriptions, and messages. A controlled textarea uses the value and onChange props.

import { useState } from "react";
function FeedbackForm() {
  const [feedback, setFeedback] = useState("");
  return (
    <div>
      <label htmlFor="feedback">Your Feedback:</label>
      <textarea
        id="feedback"
        value={feedback}
        onChange={(event) => setFeedback(event.target.value)}
        rows={4}
        placeholder="Write your feedback here"
      />
      <p>Characters: {feedback.length}</p>
    </div>
  );
}
export default FeedbackForm;

Unlike traditional HTML, React controlled textareas use the value prop to specify their current text.


9. Controlled Dropdown Using select

A controlled dropdown allows React to manage which option is selected. Use value on the select element and update its state with onChange.

import { useState } from "react";
function CourseSelector() {
  const [course, setCourse] = useState("");
  return (
    <div>
      <label htmlFor="course">Select a Course:</label>
      <select
        id="course"
        value={course}
        onChange={(event) => setCourse(event.target.value)}
      >
        <option value="">Choose a course</option>
        <option value="react">React JS</option>
        <option value="flutter">Flutter</option>
        <option value="figma">Figma UI/UX</option>
      </select>
      <p>Selected Course: {course || "None"}</p>
    </div>
  );
}
export default CourseSelector;

The value of the select element determines the selected option. In a controlled dropdown, set the selected value on the parent element instead of using the HTML selected attribute on individual options.


10. Controlled Checkbox

A checkbox is used for choices that can be independently selected, such as accepting terms and conditions or subscribing to a newsletter. Use checked to control its state.

import { useState } from "react";
function TermsCheckbox() {
  const [accepted, setAccepted] = useState(false);
  return (
    <div>
      <label>
        <input
          type="checkbox"
          checked={accepted}
          onChange={(event) => setAccepted(event.target.checked)}
        />
        I accept the terms and conditions.
      </label>
      <p>Status: {accepted ? "Accepted" : "Not accepted"}</p>
    </div>
  );
}
export default TermsCheckbox;

Important: Use event.target.checked to read whether the checkbox is selected. Do not use value to control whether it is checked.


11. Controlled Radio Buttons

Radio buttons allow users to choose one option from a group. Each option shares the same name, and its checked prop depends on the current state.

import { useState } from "react";
function LearningMode() {
  const [mode, setMode] = useState("online");
  return (
    <div>
      <p>Select Learning Mode:</p>
      <label>
        <input
          type="radio"
          name="mode"
          value="online"
          checked={mode === "online"}
          onChange={(event) => setMode(event.target.value)}
        />
        Online
      </label>
      <label>
        <input
          type="radio"
          name="mode"
          value="classroom"
          checked={mode === "classroom"}
          onChange={(event) => setMode(event.target.value)}
        />
        Classroom
      </label>
      <p>Selected Mode: {mode}</p>
    </div>
  );
}
export default LearningMode;

When the user selects a radio button, React updates mode. The matching option becomes selected because its checked condition evaluates to true.


12. Managing Multiple Fields with One State Object

When a form contains several inputs, you can keep their values in a single object instead of creating a separate state variable for every field.

import { useState } from "react";
function UserForm() {
  const [formData, setFormData] = useState({
    name: "",
    email: "",
    phone: ""
  });
  function handleChange(event) {
    const { name, value } = event.target;
    setFormData((previousData) => ({
      ...previousData,
      [name]: value
    }));
  }
  return (
    <form>
      <label htmlFor="name">Name:</label>
      <input
        id="name"
        name="name"
        value={formData.name}
        onChange={handleChange}
      />
      <label htmlFor="email">Email:</label>
      <input
        id="email"
        name="email"
        type="email"
        value={formData.email}
        onChange={handleChange}
      />
      <label htmlFor="phone">Phone:</label>
      <input
        id="phone"
        name="phone"
        type="tel"
        value={formData.phone}
        onChange={handleChange}
      />
      <pre>{JSON.stringify(formData, null, 2)}</pre>
    </form>
  );
}
export default UserForm;

Understanding the Code

  • formData stores all field values in one object.
  • name identifies which property should be updated.
  • value contains the latest value of the edited field.
  • ...previousData preserves the values of other fields.
  • [name]: value updates the matching property dynamically.
  • JSON.stringify() displays the state object for demonstration purposes.

13. Handling Form Submission

Controlled components make it straightforward to access form values during submission because the values are already stored in React state.

import { useState } from "react";
function LoginForm() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  function handleSubmit(event) {
    event.preventDefault();
    console.log("Username:", username);
    console.log("Password length:", password.length);
    alert("Form submitted!");
  }
  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="username">Username:</label>
      <input
        id="username"
        value={username}
        onChange={(event) => setUsername(event.target.value)}
        required
      />
      <label htmlFor="password">Password:</label>
      <input
        id="password"
        type="password"
        value={password}
        onChange={(event) => setPassword(event.target.value)}
        required
      />
      <button type="submit">Login</button>
    </form>
  );
}
export default LoginForm;

Explanation:

  • onSubmit runs when the form is submitted.
  • event.preventDefault() prevents the browser's default form navigation or reload.
  • username and password contain the current state values.
  • required enables built-in browser validation for empty fields.

Security note: This example demonstrates form handling only. Do not log actual passwords in a production application. Authentication should use a secure backend.


14. Validation in Controlled Components

Validation checks whether user input satisfies the application's requirements. Since controlled components keep input values in state, those values can be checked before the form is submitted.

Example: Name Validation

import { useState } from "react";
function NameValidationForm() {
  const [name, setName] = useState("");
  const [error, setError] = useState("");
  const [success, setSuccess] = useState("");
  function handleSubmit(event) {
    event.preventDefault();
    if (!name.trim()) {
      setError("Name is required.");
      setSuccess("");
      return;
    }
    setError("");
    setSuccess("Form submitted successfully!");
  }
  return (
    <form onSubmit={handleSubmit} noValidate>
      <label htmlFor="name">Name:</label>
      <input
        id="name"
        value={name}
        onChange={(event) => setName(event.target.value)}
        aria-invalid={Boolean(error)}
        aria-describedby={error ? "name-error" : undefined}
      />
      {error && <p id="name-error" role="alert">{error}</p>}
      {success && <p role="status">{success}</p>}
      <button type="submit">Submit</button>
    </form>
  );
}
export default NameValidationForm;

The noValidate attribute disables the browser's automatic validation interface for this example, allowing the custom React error message to be demonstrated. The application should still implement the validation rules it requires.


15. Resetting Controlled Form Fields

To reset a controlled form, update the React state variables to their initial values. Changing only the DOM is not sufficient because React state controls the displayed values.

import { useState } from "react";
function ResetForm() {
  const initialValues = { name: "", email: "" };
  const [formData, setFormData] = useState(initialValues);
  function handleChange(event) {
    const { name, value } = event.target;
    setFormData((previous) => ({
      ...previous,
      [name]: value
    }));
  }
  function handleReset() {
    setFormData(initialValues);
  }
  return (
    <form onReset={handleReset}>
      <input
        name="name"
        placeholder="Name"
        value={formData.name}
        onChange={handleChange}
      />
      <input
        name="email"
        type="email"
        placeholder="Email"
        value={formData.email}
        onChange={handleChange}
      />
      <button type="reset">Reset Form</button>
    </form>
  );
}
export default ResetForm;

When the reset button is clicked, the form's reset event calls handleReset(), which restores the controlled fields to empty strings.


16. Controlled vs. Uncontrolled Components

Feature Controlled Component Uncontrolled Component
Value management Managed by React state. Managed by the DOM.
Common props value or checked. defaultValue or defaultChecked.
Change handling Usually uses onChange to update state. Can rely on the browser's normal input behavior.
Access to current value Available through React state. Can be read with a ref or FormData.
Validation Easy to integrate with state-based validation. Can use browser validation or custom validation.
Programmatic updates Update the corresponding state. Usually requires DOM access or a form reset.
Best suited for Dynamic forms, live feedback, and complex interactions. Simple forms that need values mainly at submission time.

17. Common Mistakes in Controlled Components

Mistake Problem Correct Approach
Missing onChange The controlled input cannot be edited normally. Add an event handler that updates state.
Using value for a checkbox's selected state The checkbox selection is not controlled correctly. Use checked.
Using event.target.value for checkbox selection It reads the checkbox's data value, not whether it is checked. Use event.target.checked.
Initializing text state with undefined The input may switch from uncontrolled to controlled. Initialize text state with "".
Updating state asynchronously in onChange The displayed value may revert or the cursor may behave unexpectedly. Update the controlled value synchronously.
Replacing the entire state object accidentally Other input values may be lost. Preserve existing properties with the spread operator.
Using an incorrect button type A button may submit a form unexpectedly. Use type="button" for ordinary actions and type="submit" for submission.

18. Best Practices for Controlled Components

  • Use useState to store input values when the UI needs to react to changes.
  • Provide an onChange handler whenever an editable input is controlled by value or checked.
  • Initialize text values with strings and checkbox values with booleans.
  • Update controlled input state synchronously inside the change handler.
  • Use meaningful state names, such as email, username, and isAccepted.
  • Use the functional state-update form when the new object depends on previous state.
  • Use labels and accessible error messages.
  • Validate data before submission and on the server when security or data integrity matters.
  • Avoid storing sensitive information unnecessarily or printing it in logs.
  • For large forms, consider separating fields into smaller components to improve maintainability and rendering performance.

19. Performance Considerations

Controlled inputs usually update React state on each change, which causes the component that owns the state to render again. For most forms, this behavior is expected and performs well.

  • Keep form state in the smallest component that needs it.
  • Avoid placing frequently updated form state at the top of a very large component tree unless necessary.
  • Separate unrelated page content from the component that handles frequent input changes.
  • Use memoization or deferred rendering only when profiling shows a real performance problem.

Example: If a search input updates on every keystroke, keep its state close to the search component rather than making the entire application depend on that state unnecessarily.


20. Complete Mini Project: Controlled Student Registration Form

This mini project combines controlled text inputs, a dropdown, a checkbox, validation, submission handling, and success messages.

import { useState } from "react";
function StudentRegistration() {
  const initialForm = {
    name: "",
    email: "",
    course: "",
    acceptedTerms: false
  };
  const [form, setForm] = useState(initialForm);
  const [errors, setErrors] = useState({});
  const [message, setMessage] = useState("");
  function handleChange(event) {
    const { name, value, checked, type } = event.target;
    setForm((previous) => ({
      ...previous,
      [name]: type === "checkbox" ? checked : value
    }));
    setErrors((previous) => ({
      ...previous,
      [name]: ""
    }));
    setMessage("");
  }
  function handleSubmit(event) {
    event.preventDefault();
    const nextErrors = {};
    if (!form.name.trim()) {
      nextErrors.name = "Please enter your name.";
    }
    if (!form.email.trim()) {
      nextErrors.email = "Please enter your email.";
    } else if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(form.email)) {
      nextErrors.email = "Please enter a valid email address.";
    }
    if (!form.course) {
      nextErrors.course = "Please select a course.";
    }
    if (!form.acceptedTerms) {
      nextErrors.acceptedTerms = "Please accept the terms.";
    }
    setErrors(nextErrors);
    if (Object.keys(nextErrors).length === 0) {
      setMessage("Registration submitted successfully!");
      console.log("Registration details:", {
        name: form.name,
        email: form.email,
        course: form.course,
        acceptedTerms: form.acceptedTerms
      });
    } else {
      setMessage("Please correct the errors below.");
    }
  }
  function handleReset() {
    setForm(initialForm);
    setErrors({});
    setMessage("");
  }
  return (
    <form onSubmit={handleSubmit} onReset={handleReset} noValidate>
      <h2>Student Registration</h2>
      <label htmlFor="name">Full Name:</label>
      <input
        id="name"
        name="name"
        value={form.name}
        onChange={handleChange}
        aria-invalid={Boolean(errors.name)}
      />
      {errors.name && <p role="alert">{errors.name}</p>}
      <label htmlFor="email">Email Address:</label>
      <input
        id="email"
        name="email"
        type="email"
        value={form.email}
        onChange={handleChange}
        aria-invalid={Boolean(errors.email)}
      />
      {errors.email && <p role="alert">{errors.email}</p>}
      <label htmlFor="course">Select Course:</label>
      <select
        id="course"
        name="course"
        value={form.course}
        onChange={handleChange}
        aria-invalid={Boolean(errors.course)}
      >
        <option value="">Choose a course</option>
        <option value="react">React JS</option>
        <option value="flutter">Flutter</option>
        <option value="figma">Figma UI/UX</option>
      </select>
      {errors.course && <p role="alert">{errors.course}</p>}
      <label>
        <input
          type="checkbox"
          name="acceptedTerms"
          checked={form.acceptedTerms}
          onChange={handleChange}
        />
        I accept the terms and conditions.
      </label>
      {errors.acceptedTerms && (
        <p role="alert">{errors.acceptedTerms}</p>
      )}
      {message && <p role="status">{message}</p>}
      <button type="submit">Register</button>
      <button type="reset">Reset Form</button>
    </form>
  );
}
export default StudentRegistration;

Project Workflow

  1. The user enters their name and email address.
  2. The user selects a course from the dropdown.
  3. The user accepts the terms and conditions.
  4. The user clicks the Register button.
  5. React validates the entered information.
  6. If errors exist, React displays messages next to the relevant fields.
  7. If all checks pass, the form displays a success message.
  8. The Reset Form button restores the initial state.

Note: This is a front-end demonstration. It does not save registration data to a database. A real application should send the data to a secure backend and validate it on the server.


21. Interview Questions and Answers

Q1. What is a controlled component in React?

A controlled component is a form element whose current value or selected state is managed by React state.

Q2. Why are controlled components useful?

They make it easier to validate input, display dynamic content, update values programmatically, and manage form submission.

Q3. Which Hook is commonly used for controlled components?

The useState Hook is commonly used to store and update form field values in functional components.

Q4. What is the role of the value prop?

The value prop controls the current value of text inputs, textareas, and select elements.

Q5. What is the role of the checked prop?

The checked prop controls whether a checkbox or radio button is selected.

Q6. Why is onChange important?

The onChange handler reads user input and updates React state. A controlled input normally needs this handler to remain editable.

Q7. What is the difference between value and defaultValue?

value controls the current value through React, while defaultValue specifies the initial value of an uncontrolled input.

Q8. Can checkboxes be controlled components?

Yes. Use checked to represent the selected state and onChange to update the state.

Q9. How do you manage multiple inputs with one handler?

Give each input a unique name attribute and use event.target.name and event.target.value to update the matching property in a state object.

Q10. What happens if a controlled input has value but no onChange?

The input behaves as read-only because React keeps forcing the specified value. Add an onChange handler or use readOnly if the field is intentionally non-editable.


22. Practice Exercises

  1. Create a controlled input that displays the user's name as they type.
  2. Build a controlled email field with email-format validation.
  3. Create a password input and display its character count.
  4. Build a controlled textarea for collecting feedback.
  5. Create a dropdown for selecting a training course.
  6. Build a checkbox for accepting terms and conditions.
  7. Create radio buttons for choosing online or classroom learning.
  8. Manage name, email, and phone fields with one state object.
  9. Build a controlled login form with submission handling.
  10. Create a registration form with validation, error messages, and a reset button.

23. Quick Revision Checklist

  • Understand the definition of controlled components.
  • Know how React state controls form values.
  • Use useState to manage input values.
  • Use value for text inputs, textareas, and dropdowns.
  • Use checked for checkboxes and radio buttons.
  • Handle input changes with onChange.
  • Manage multiple fields using one state object.
  • Validate input before submission.
  • Handle form submission with onSubmit.
  • Reset controlled values by updating React state.
  • Keep controlled values initialized to appropriate types.
  • Understand the difference between controlled and uncontrolled components.

24. Official Learning Resources


25. Conclusion

Controlled components are an important part of form handling in React JS. They allow React state to manage user input and provide a predictable way to validate, update, reset, and submit form data. By practicing text inputs, checkboxes, radio buttons, dropdowns, and multi-field forms, you can build interactive and maintainable React applications.

Explore the Course: JustAcademy React JS Training Course | Register for React JS Course Demo

whatsapp