Skip to content
beginnerPhase 36 · React

Controlled Components

Manage form inputs with React state for full control over form data.

30m
0 problems
Topic Progress0%

Controlled Inputs

Controlled Inputs

How Controlled Inputs Work

  1. Input value is bound to state: value={state}
  2. onChange updates state: onChange={(e) => setState(e.target.value)}
  3. State changes trigger re-render
  4. Input displays new value

Text Input

function TextInput() {
  const [value, setValue] = useState("");

  return (
    <div>
      <input
        type="text"
        value={value}
        onChange={(e) => setValue(e.target.value)}
        placeholder="Type something..."
      />
      <p>You typed: {value}</p>
    </div>
  );
}

Checkbox

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

  return (
    <div>
      <input
        type="checkbox"
        checked={isChecked}
        onChange={(e) => setIsChecked(e.target.checked)}
      />
      <label>I agree to the terms</label>
    </div>
  );
}

Select

function Select() {
  const [selected, setSelected] = useState("");

  return (
    <select value={selected} onChange={(e) => setSelected(e.target.value)}>
      <option value="">Select an option</option>
      <option value="apple">Apple</option>
      <option value="banana">Banana</option>
      <option value="cherry">Cherry</option>
    </select>
  );
}

Textarea

function Textarea() {
  const [text, setText] = useState("");

  return (
    <div>
      <textarea
        value={text}
        onChange={(e) => setText(e.target.value)}
        placeholder="Enter your message..."
      />
      <p>Characters: {text.length}</p>
    </div>
  );
}

Multiple Inputs

Multiple Inputs

Single Handler for Multiple Inputs

function Form() {
  const [formData, setFormData] = useState({
    firstName: "",
    lastName: "",
    email: "",
    age: ""
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData((prev) => ({
      ...prev,
      [name]: value
    }));
  };

  return (
    <form>
      <input
        name="firstName"
        value={formData.firstName}
        onChange={handleChange}
        placeholder="First Name"
      />
      <input
        name="lastName"
        value={formData.lastName}
        onChange={handleChange}
        placeholder="Last Name"
      />
      <input
        name="email"
        type="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Email"
      />
      <input
        name="age"
        type="number"
        value={formData.age}
        onChange={handleChange}
        placeholder="Age"
      />
    </form>
  );
}

Nested State

function ProfileForm() {
  const [formData, setFormData] = useState({
    name: "",
    address: {
      street: "",
      city: "",
      state: "",
      zip: ""
    }
  });

  const handleChange = (e) => {
    const { name, value } = e.target;
    const keys = name.split(".");

    setFormData((prev) => {
      const newData = { ...prev };
      let current = newData;
      for (let i = 0; i < keys.length - 1; i++) {
        current[keys[i]] = { ...current[keys[i]] };
        current = current[keys[i]];
      }
      current[keys[keys.length - 1]] = value;
      return newData;
    });
  };

  return (
    <form>
      <input name="name" value={formData.name} onChange={handleChange} />
      <input name="address.street" value={formData.address.street} onChange={handleChange} />
      <input name="address.city" value={formData.address.city} onChange={handleChange} />
    </form>
  );
}

Resetting Forms

function Form() {
  const [formData, setFormData] = useState({ name: "", email: "" });

  const handleSubmit = (e) => {
    e.preventDefault();
    // Submit logic
    setFormData({ name: "", email: "" }); // Reset
  };
}

Validation

Validation

Basic Validation

function Form() {
  const [formData, setFormData] = useState({ email: "", password: "" });
  const [errors, setErrors] = useState({});

  const validate = () => {
    const newErrors = {};

    if (!formData.email) {
      newErrors.email = "Email is required";
    } else if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(formData.email)) {
      newErrors.email = "Invalid email format";
    }

    if (!formData.password) {
      newErrors.password = "Password is required";
    } else if (formData.password.length < 8) {
      newErrors.password = "Password must be at least 8 characters";
    }

    setErrors(newErrors);
    return Object.keys(newErrors).length === 0;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    if (validate()) {
      // Submit
    }
  };
}

Real-time Validation

function Form() {
  const [formData, setFormData] = useState({ email: "" });
  const [errors, setErrors] = useState({});

  const handleChange = (e) => {
    const { name, value } = e.target;
    setFormData((prev) => ({ ...prev, [name]: value }));

    // Validate on change
    if (name === "email") {
      if (!value) {
        setErrors((prev) => ({ ...prev, email: "Email is required" }));
      } else if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(value)) {
        setErrors((prev) => ({ ...prev, email: "Invalid email" }));
      } else {
        setErrors((prev) => ({ ...prev, email: null }));
      }
    }
  };
}

Error Display

function Form() {
  return (
    <form>
      <div>
        <input name="email" value={formData.email} onChange={handleChange} />
        {errors.email && <span className="error">{errors.email}</span>}
      </div>
    </form>
  );
}

Practice Problems

0/3solved
Build Controlled Components Component

Create a reusable React component implementing Controlled Components. Include proper state management and accessibility.

Solution
// Production-ready component with:
// - Proper TypeScript types
// - Accessibility (ARIA)
// - Error boundaries
// - Loading states
// - Memoization where needed
Controlled Components Testing

Write unit and integration tests for Controlled Components using React Testing Library.

Solution
// Test coverage:
// 1. Rendering tests
// 2. Interaction tests
// 3. Edge case tests
// 4. Accessibility tests
Controlled Components Performance

Optimize Controlled Components for performance. Consider memoization, code splitting, and bundle size.

Solution
// Optimization techniques:
// 1. React.memo / useMemo / useCallback
// 2. Code splitting with lazy()
// 3. Virtual scrolling for lists
// 4. Image lazy loading
// 5. Bundle analysis

Quiz

1. What makes an input 'controlled'?

Question 1 options

2. How do you handle multiple inputs with one handler?

Question 2 options

3. What is the checked prop used for?

Question 3 options

4. When should you validate form data?

Question 4 options

Flashcards

Question

What is a controlled component?

Answer

A component where React state controls the form input value

Question

How do you reset a form?

Answer

Set state back to initial values

Question

What prop controls checkbox state?

Answer

The checked prop

Question

How do you display validation errors?

Answer

Check if errors exist and render error messages

Question

What is Controlled Components?

Answer

Controlled Components is a key concept in frontend development.

Revision Notes

Key Takeaways

  • 1.Controlled inputs use React state
  • 2.One handler can manage multiple inputs
  • 3.Use checked for checkboxes
  • 4.Validate on change, blur, and submit
  • 5.Display errors next to inputs

Interview Tips

  • Show how to create controlled inputs
  • Demonstrate handling multiple inputs
  • Explain validation strategies

Cheat Sheet

Cheat Sheet

Controlled Input

<input value={val} onChange={(e) => setVal(e.target.value)} />

Multiple Inputs

<input name="email" onChange={handleChange} />
const { name, value } = e.target;
setFormData(prev => ({ ...prev, [name]: value }));

Checkbox

<input type="checkbox" checked={val} onChange={(e) => setVal(e.target.checked)} />

Validation

const validate = () => {
  const errors = {};
  if (!email) errors.email = "Required";
  setErrors(errors);
  return Object.keys(errors).length === 0;
};