# React Forms & Controlled Components

Almost every real-world web application needs forms.

A user might need to:

```text
Enter their name
Enter their email
Choose a role
Enter a password
Select a preference
Submit the form
```

In vanilla JavaScript, we can access form elements directly from the DOM.

React takes a different approach.

Instead of letting the DOM be the primary source of truth, we can store form values in **React State**.

This pattern is called a **Controlled Component**.

* * *

# 🧠 What Is a Form in React?

A normal HTML form might look like:

```html
<form>
  <input type="text" />
  <button type="submit">Submit</button>
</form>
```

In React, we can connect the input to state:

```jsx
const [name, setName] = useState("");
```

Then:

```jsx
<input
  value={name}
  onChange={event => setName(event.target.value)}
/>
```

Now React knows the current value of the input.

The flow becomes:

```text
User types
    ↓
onChange
    ↓
event.target.value
    ↓
setName()
    ↓
State updates
    ↓
Input re-renders
```

* * *

# ⚛️ What Is a Controlled Component?

A controlled input is an input whose value is controlled by React state.

Example:

```jsx
import { useState } from "react";

function App() {
  const [name, setName] = useState("");

  return (
    <input
      value={name}
      onChange={event => setName(event.target.value)}
    />
  );
}
```

Here:

```jsx
value={name}
```

means React controls the input's value.

And:

```jsx
onChange={event => setName(event.target.value)}
```

updates that state whenever the user types.

So:

```text
React State
     ↓
   Input
     ↓
User types
     ↓
onChange
     ↓
React State
```

This is called **controlled input** or **controlled component**.

* * *

# 🔄 Why Controlled Components Matter

At first, you might think:

> "Why not just read the input when the user submits?"

Because controlling inputs gives React access to the current value **at all times**.

That means we can easily:

*   Validate input
    
*   Disable buttons
    
*   Display live previews
    
*   Show character counts
    
*   Enable/disable fields
    
*   Transform values
    
*   Display error messages
    
*   Submit data to APIs
    

For example:

```jsx
<p>{name.length}/50 characters</p>
```

Because React already knows the current value.

* * *

# 📝 Basic Text Input

Let's start with a simple name input.

```jsx
import { useState } from "react";

function App() {
  const [name, setName] = useState("");

  function handleNameChange(event) {
    setName(event.target.value);
  }

  return (
    <div>
      <label>Name:</label>

      <input
        type="text"
        value={name}
        onChange={handleNameChange}
      />

      <p>Your name: {name}</p>
    </div>
  );
}

export default App;
```

If the user types:

```text
Saurabh
```

the state becomes:

```js
"Saurabh"
```

and the UI updates immediately.

* * *

# 🎯 `event.target.value`

This is one of the most important things to remember.

For:

```jsx
<input onChange={handleChange} />
```

we can write:

```jsx
function handleChange(event) {
  console.log(event.target.value);
}
```

If the user types:

```text
React
```

then:

```js
event.target.value
```

contains:

```text
"React"
```

This is how we retrieve what the user entered.

* * *

# 📧 Handling Multiple Inputs

Real forms usually have multiple fields.

For example:

```text
Name
Email
Password
```

We could create separate state variables:

```jsx
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
```

Then:

```jsx
<input
  value={name}
  onChange={event => setName(event.target.value)}
/>

<input
  value={email}
  onChange={event => setEmail(event.target.value)}
/>

<input
  value={password}
  onChange={event => setPassword(event.target.value)}
/>
```

This works perfectly well.

But for larger forms, there's another useful pattern.

* * *

# 📦 Managing Form Data With One Object

Instead of:

```jsx
const [name, setName] = useState("");
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
```

we can use:

```jsx
const [formData, setFormData] = useState({
  name: "",
  email: "",
  password: ""
});
```

Now all form data lives inside one object.

* * *

# 🔄 Updating Object State

Suppose the user changes the name.

We can write:

```jsx
setFormData({
  ...formData,
  name: event.target.value
});
```

The spread operator keeps the existing fields.

For example:

```js
{
  name: "Saurabh",
  email: "",
  password: ""
}
```

If the email changes:

```jsx
setFormData({
  ...formData,
  email: event.target.value
});
```

The other values remain unchanged.

* * *

# 🧠 Dynamic Input Handling With `name`

We can make this much cleaner.

Give each input a `name`:

```jsx
<input
  name="name"
  value={formData.name}
  onChange={handleChange}
/>

<input
  name="email"
  value={formData.email}
  onChange={handleChange}
/>
```

Then create one handler:

```jsx
function handleChange(event) {
  const { name, value } = event.target;

  setFormData({
    ...formData,
    [name]: value
  });
}
```

This is a very useful React form pattern.

* * *

# 🔍 Understanding `[name]: value`

This syntax:

```jsx
[name]: value
```

is a **computed property name** in JavaScript.

Suppose:

```js
name = "email";
value = "test@example.com";
```

Then:

```js
{
  [name]: value
}
```

becomes:

```js
{
  email: "test@example.com"
}
```

If:

```js
name = "username";
```

it becomes:

```js
{
  username: "..."
}
```

This allows one event handler to manage multiple fields.

* * *

# 🚀 Complete Multi-Input Form

```jsx
import { useState } from "react";

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

  function handleChange(event) {
    const { name, value } = event.target;

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

  function handleSubmit(event) {
    event.preventDefault();

    console.log(formData);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="text"
        name="name"
        value={formData.name}
        onChange={handleChange}
        placeholder="Name"
      />

      <input
        type="email"
        name="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Email"
      />

      <input
        type="password"
        name="password"
        value={formData.password}
        onChange={handleChange}
        placeholder="Password"
      />

      <button type="submit">
        Register
      </button>
    </form>
  );
}

export default RegistrationForm;
```

Notice the pattern:

```text
Input
 ↓
name + value
 ↓
handleChange
 ↓
setFormData()
 ↓
State
```

This pattern is worth memorizing.

* * *

# 📤 Handling Form Submission

Forms use:

```jsx
onSubmit
```

Example:

```jsx
<form onSubmit={handleSubmit}>
```

Handler:

```jsx
function handleSubmit(event) {
  event.preventDefault();

  console.log("Submitted!");
}
```

The:

```jsx
event.preventDefault();
```

prevents the browser's default form submission behavior.

Now React can handle the submission.

* * *

# 🛑 Why Use `preventDefault()`?

Without it, the browser may perform its normal form submission behavior.

In a React single-page application, we usually want to:

```text
Collect data
    ↓
Validate data
    ↓
Send API request
    ↓
Show result
```

instead of allowing the browser to navigate/reload as part of the default submission.

* * *

# 🔐 Password Input

Password fields work exactly like normal controlled inputs:

```jsx
const [password, setPassword] = useState("");
```

Then:

```jsx
<input
  type="password"
  value={password}
  onChange={event => setPassword(event.target.value)}
/>
```

We can later combine this with conditional rendering to create:

```text
Password: ********

[ Show Password ]
```

* * *

# 📋 Textarea

A `<textarea>` can also be controlled.

```jsx
const [message, setMessage] = useState("");
```

Then:

```jsx
<textarea
  value={message}
  onChange={event => setMessage(event.target.value)}
/>
```

Example:

```jsx
function MessageForm() {
  const [message, setMessage] = useState("");

  return (
    <div>
      <textarea
        value={message}
        onChange={event => setMessage(event.target.value)}
        placeholder="Write a message..."
      />

      <p>{message.length} characters</p>
    </div>
  );
}
```

* * *

# 🔘 Checkbox

Checkboxes are slightly different.

Instead of:

```jsx
value
```

we generally control:

```jsx
checked
```

Example:

```jsx
const [accepted, setAccepted] = useState(false);
```

Then:

```jsx
<input
  type="checkbox"
  checked={accepted}
  onChange={event => setAccepted(event.target.checked)}
/>
```

Notice:

```jsx
event.target.checked
```

rather than:

```jsx
event.target.value
```

* * *

# 🧠 Why `checked`?

A checkbox has a boolean state:

```text
true
false
```

So:

```jsx
checked={accepted}
```

makes more semantic sense.

Example:

```jsx
<label>
  <input
    type="checkbox"
    checked={accepted}
    onChange={event => setAccepted(event.target.checked)}
  />

  I accept the terms
</label>
```

Now `accepted` will be either:

```js
true
```

or:

```js
false
```

* * *

# 🔘 Radio Buttons

Radio buttons work similarly.

Suppose we want users to select a role:

```text
○ Frontend Developer
○ Backend Developer
○ Full Stack Developer
```

State:

```jsx
const [role, setRole] = useState("");
```

Then:

```jsx
<label>
  <input
    type="radio"
    name="role"
    value="frontend"
    checked={role === "frontend"}
    onChange={event => setRole(event.target.value)}
  />

  Frontend Developer
</label>
```

Another:

```jsx
<label>
  <input
    type="radio"
    name="role"
    value="backend"
    checked={role === "backend"}
    onChange={event => setRole(event.target.value)}
  />

  Backend Developer
</label>
```

The state stores the selected value.

* * *

# 🔽 Select Dropdown

A `<select>` can also be controlled.

```jsx
const [country, setCountry] = useState("");
```

Then:

```jsx
<select
  value={country}
  onChange={event => setCountry(event.target.value)}
>
  <option value="">Select Country</option>
  <option value="india">India</option>
  <option value="usa">USA</option>
  <option value="uk">UK</option>
</select>
```

Now:

```text
User selects India
       ↓
onChange
       ↓
event.target.value
       ↓
setCountry("india")
```

* * *

# 🧩 Form Validation

Forms shouldn't blindly accept anything.

We can validate data before submitting.

For example:

```jsx
function handleSubmit(event) {
  event.preventDefault();

  if (!formData.name) {
    alert("Name is required");
    return;
  }

  if (!formData.email) {
    alert("Email is required");
    return;
  }

  console.log("Form submitted!");
}
```

The logic becomes:

```text
Submit
  ↓
Validate
  ↓
Invalid?
 ├── Yes → Show error
 └── No  → Submit
```

* * *

# ❌ Displaying Validation Errors

Instead of using `alert()`, we can store errors in state.

```jsx
const [error, setError] = useState("");
```

Then:

```jsx
if (!formData.name) {
  setError("Name is required");
  return;
}
```

Display:

```jsx
{error && <p>{error}</p>}
```

This uses the conditional rendering concept we learned on Day 65.

* * *

# 🔥 Multiple Validation Errors

For larger forms, we can store errors as an object:

```jsx
const [errors, setErrors] = useState({});
```

Example:

```jsx
setErrors({
  name: "Name is required",
  email: "Invalid email"
});
```

Then:

```jsx
{errors.name && (
  <p>{errors.name}</p>
)}
```

and:

```jsx
{errors.email && (
  <p>{errors.email}</p>
)}
```

This gives us much more control.

* * *

# 🧠 Validation + Conditional Rendering

Suppose:

```jsx
{errors.email && (
  <span>{errors.email}</span>
)}
```

If:

```js
errors.email
```

contains:

```text
"Invalid email"
```

we show the message.

If it doesn't exist:

```js
undefined
```

nothing is displayed.

This is another example of combining concepts from previous days.

* * *

# 🔢 Input Validation Example

We can validate an email:

```jsx
function validateEmail(email) {
  return email.includes("@");
}
```

Then:

```jsx
if (!validateEmail(formData.email)) {
  setErrors({
    email: "Please enter a valid email"
  });

  return;
}
```

For production applications, validation requirements are usually more comprehensive, but this demonstrates the basic idea.

* * *

# 🚫 Disabling Submit Buttons

We can prevent submission until required fields are filled.

For example:

```jsx
<button
  type="submit"
  disabled={!formData.email || !formData.password}
>
  Login
</button>
```

If either field is empty, the button is disabled.

This is a great example of:

```text
State
 ↓
Condition
 ↓
UI behavior
```

* * *

# 🔄 Resetting a Form

After successful submission, we may want to clear the form.

```jsx
setFormData({
  name: "",
  email: "",
  password: ""
});
```

For example:

```jsx
function handleSubmit(event) {
  event.preventDefault();

  console.log(formData);

  setFormData({
    name: "",
    email: "",
    password: ""
  });
}
```

Now the inputs return to their initial values.

* * *

# 🧠 Controlled vs Uncontrolled Components

There are two broad approaches.

### Controlled

React state controls the value:

```jsx
<input
  value={name}
  onChange={handleChange}
/>
```

### Uncontrolled

The DOM keeps track of the value, often accessed through a ref.

For example:

```jsx
<input ref={inputRef} />
```

For many everyday React forms, **controlled components are a straightforward and predictable approach**.

We'll learn more about refs later.

* * *

# 📊 Controlled Component Mental Model

Remember this:

```text
         React State
              ↓
           value
              ↓
            Input
              ↓
         User types
              ↓
          onChange
              ↓
        setState(...)
              ↓
         React State
```

React stays in control of the data.

* * *

# 🔥 Complete Registration Form

Let's put everything together.

```jsx
import { useState } from "react";

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

  const [error, setError] = useState("");

  function handleChange(event) {
    const { name, value } = event.target;

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

  function handleSubmit(event) {
    event.preventDefault();

    if (!formData.name) {
      setError("Name is required");
      return;
    }

    if (!formData.email) {
      setError("Email is required");
      return;
    }

    if (!formData.password) {
      setError("Password is required");
      return;
    }

    setError("");

    console.log("Registration successful!");
    console.log(formData);
  }

  return (
    <form onSubmit={handleSubmit}>
      <h1>Create Account</h1>

      {error && (
        <p>{error}</p>
      )}

      <input
        type="text"
        name="name"
        value={formData.name}
        onChange={handleChange}
        placeholder="Name"
      />

      <input
        type="email"
        name="email"
        value={formData.email}
        onChange={handleChange}
        placeholder="Email"
      />

      <input
        type="password"
        name="password"
        value={formData.password}
        onChange={handleChange}
        placeholder="Password"
      />

      <select
        name="role"
        value={formData.role}
        onChange={handleChange}
      >
        <option value="">Select Role</option>
        <option value="frontend">
          Frontend Developer
        </option>
        <option value="backend">
          Backend Developer
        </option>
        <option value="fullstack">
          Full Stack Developer
        </option>
      </select>

      <button type="submit">
        Register
      </button>
    </form>
  );
}

export default RegistrationForm;
```

This single example uses:

*   `useState`
    
*   Controlled inputs
    
*   `onChange`
    
*   `onSubmit`
    
*   `event.target`
    
*   Computed property names
    
*   Object state
    
*   Conditional rendering
    
*   Validation
    
*   Select inputs
    
*   Error handling
    
*   Form reset concepts
    

* * *

# 🏆 Best Practices

### 1\. Give inputs meaningful `name` attributes

```jsx
name="email"
```

This makes generic handlers much easier.

* * *

### 2\. Keep form state predictable

For example:

```jsx
const [formData, setFormData] = useState({
  name: "",
  email: "",
  password: ""
});
```

* * *

### 3\. Use functional state updates for object state

Prefer:

```jsx
setFormData(prev => ({
  ...prev,
  [name]: value
}));
```

This clearly updates based on the previous state.

* * *

### 4\. Validate before submitting

Don't assume the user entered valid data.

* * *

### 5\. Give useful error messages

Instead of:

```text
Error
```

prefer:

```text
Please enter a valid email address.
```

* * *

### 6\. Keep validation logic separate when it gets complex

As applications grow, move validation into dedicated functions or utilities.

* * *

### 7\. Don't store unnecessary derived state

For example, if you can calculate:

```jsx
const isFormValid =
  formData.email !== "" &&
  formData.password !== "";
```

you don't necessarily need another state variable just for `isFormValid`.

* * *

# 💡 My Biggest Takeaway

Today's biggest takeaway is:

> **A controlled form is essentially a conversation between React State and the user.**

The user types:

```text
User Input
    ↓
onChange
    ↓
State
    ↓
UI
```

And when the user submits:

```text
Submit
 ↓
onSubmit
 ↓
Validate
 ↓
Process Data
 ↓
API / Backend
```

This is extremely important because forms are the primary way users provide data to our applications.

And soon, when we connect React to a backend, this same form data can be sent to our **Node.js / Express APIs**.
