DEV Community

Cover image for React Mastery Series – Day 12: Forms in React – Building Controlled and Interactive Forms
Siva Samanthapudi
Siva Samanthapudi

Posted on

React Mastery Series – Day 12: Forms in React – Building Controlled and Interactive Forms

Welcome back to the React Mastery Series!

In the previous article, we explored Rendering Lists in React and learned how to dynamically generate UI using arrays, map(), and the importance of the key prop.

Today, we will explore one of the most important concepts in frontend development:

Forms in React

Forms are everywhere in modern applications:

  • Login and registration
  • Search functionality
  • Payment processing
  • Profile updates
  • Banking transactions
  • Checkout flows
  • User management systems

A frontend developer spends a significant amount of time building and managing forms.

React provides a powerful approach to handle forms using Controlled Components


How HTML Forms Work Traditionally

In traditional HTML applications, the browser manages form values.

Example:

<form>
  <input type="text" />

  <button>
    Submit
  </button>
</form>
Enter fullscreen mode Exit fullscreen mode

The browser stores the input value internally.

JavaScript retrieves the value when needed.


How React Handles Forms

React follows a different approach.

React keeps form data inside the component state.

The flow becomes:

User Types
     |
     ↓
onChange Event
     |
     ↓
Update React State
     |
     ↓
State Becomes Source of Truth
     |
     ↓
UI Updates
Enter fullscreen mode Exit fullscreen mode

This pattern is called Controlled Component


What is a Controlled Component?

A controlled component is a form element whose value is controlled by React state.

Example:

import { useState } from "react";

function LoginForm() {

  const [email, setEmail] = useState("");

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

}
Enter fullscreen mode Exit fullscreen mode

Here:

Input Value
     |
     ↓
React State
     |
     ↓
Component Controls Input
Enter fullscreen mode Exit fullscreen mode

React becomes the single source of truth.


Understanding value and onChange

A controlled input requires two important properties (i.e value & onChange)

value

Defines what is displayed.

value={email}
Enter fullscreen mode Exit fullscreen mode

onChange

Updates the state whenever the user types.

onChange={(event) =>
  setEmail(event.target.value)
}
Enter fullscreen mode Exit fullscreen mode

Together:

<input
  value={email}
  onChange={handleChange}
/>
Enter fullscreen mode Exit fullscreen mode

create a controlled input.


Handling Multiple Form Fields

Real applications usually contain multiple fields.

Example:

const [formData, setFormData] = useState({
  username: "",
  email: "",
  password: ""
});
Enter fullscreen mode Exit fullscreen mode

Instead of creating separate states:

const [username,setUsername] = useState("");

const [email,setEmail] = useState("");

const [password,setPassword] = useState("");
Enter fullscreen mode Exit fullscreen mode

we can manage related values together.


Updating Multiple Inputs

Example:

function RegisterForm(){

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


function handleChange(event){

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

}


return (

<form>

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


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


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

</form>

);

}
Enter fullscreen mode Exit fullscreen mode

Understanding Computed Property Names

This syntax:

[event.target.name]: event.target.value
Enter fullscreen mode Exit fullscreen mode

is a JavaScript feature called Computed Property Name

Example:

const field = "email";

const user = {
  [field]: "test@example.com"
};
Enter fullscreen mode Exit fullscreen mode

Result:

{
 email:"test@example.com"
}
Enter fullscreen mode Exit fullscreen mode

React forms use this pattern frequently.


Handling Form Submission

A form submission normally refreshes the browser page.

React applications prevent this behavior.

Example:

function LoginForm(){

function handleSubmit(event){
    event.preventDefault();
    console.log("Form Submitted");
}

return (
<form onSubmit={handleSubmit}>
    <button>Login</button>
</form>
);

}
Enter fullscreen mode Exit fullscreen mode

Why use preventDefault()?

Without:

event.preventDefault();
Enter fullscreen mode Exit fullscreen mode

The browser performs a full page refresh.

With React:

Submit Form
      |
      ↓
Prevent Browser Refresh
      |
      ↓
Validate Data
      |
      ↓
Call API
      |
      ↓
Update UI
Enter fullscreen mode Exit fullscreen mode

Form Validation

Validation ensures users enter correct information.

Common validations:

  • Required fields
  • Email format
  • Password rules
  • Minimum length
  • Business rules

Example:

if(email === ""){

setError("Email is required");

}
Enter fullscreen mode Exit fullscreen mode

Showing Validation Messages

Example:

{
error &&
<p>
  {error}
</p>
}
Enter fullscreen mode Exit fullscreen mode

This uses conditional rendering that we learned earlier.


Complete Login Form Example

import { useState } from "react";

function LoginForm(){

const [form,setForm] =
useState({
 email:"",
 password:""
});


function handleChange(event){

setForm({
 ...form,
 [event.target.name]:
 event.target.value
});

}


function handleSubmit(event){

event.preventDefault();

console.log(form);

}


return (

<form onSubmit={handleSubmit}>

<input
 name="email"
 type="email"
 value={form.email}
 onChange={handleChange}
/>


<input
 name="password"
 type="password"
 value={form.password}
 onChange={handleChange}
/>


<button>
Login
</button>


</form>

);

}

export default LoginForm;
Enter fullscreen mode Exit fullscreen mode

Handling Checkbox Inputs

Checkboxes work slightly differently.

Example:

const [accepted,setAccepted] = useState(false);
Enter fullscreen mode Exit fullscreen mode

Component:

<input
 type="checkbox"
 checked={accepted}
 onChange={(event)=>
 setAccepted(event.target.checked)
 }
/>
Enter fullscreen mode Exit fullscreen mode

Use:

event.target.checked
Enter fullscreen mode Exit fullscreen mode

instead of:

event.target.value
Enter fullscreen mode Exit fullscreen mode

Handling Select Dropdowns

Example:

const [country,setCountry] = useState("");
Enter fullscreen mode Exit fullscreen mode

Component:

<select
 value={country}
 onChange={(event)=>
 setCountry(event.target.value)
 }
>

<option>
India
</option>

<option>
UAE
</option>

</select>
Enter fullscreen mode Exit fullscreen mode

Controlled vs Uncontrolled Components

React supports two approaches.

Controlled Component

React manages the value.

<input
 value={name}
 onChange={handleChange}
/>
Enter fullscreen mode Exit fullscreen mode

Advantages:

  • Easy validation
  • Dynamic UI updates
  • Predictable behavior
  • Recommended approach

Uncontrolled Component

The DOM manages the value.

Example:

const inputRef = useRef();

<input ref={inputRef}/>
Enter fullscreen mode Exit fullscreen mode

Value is accessed directly:

inputRef.current.value
Enter fullscreen mode Exit fullscreen mode

Useful for:

  • Simple forms
  • File uploads
  • Integrating with non-React libraries

Forms in Enterprise Applications

Consider a banking application:

Fund Transfer Form

Fields:

From Account
To Account
Amount
Transfer Date
Remarks
Enter fullscreen mode Exit fullscreen mode

React flow:

User Enters Data
        |
        ↓
Update Form State
        |
        ↓
Validate Input
        |
        ↓
Submit Request
        |
        ↓
Call Transfer API
        |
        ↓
Show Success/Error Message
Enter fullscreen mode Exit fullscreen mode

This exact pattern is used in enterprise applications.


Common Form Mistakes

1. Not Providing value

Incorrect:

<input
onChange={handleChange}
/>
Enter fullscreen mode Exit fullscreen mode

The input becomes uncontrolled.


2. Forgetting name Attribute

Incorrect:

<input />
Enter fullscreen mode Exit fullscreen mode

When using a generic handler:

event.target.name
Enter fullscreen mode Exit fullscreen mode

the name attribute is required.


3. Mutating Form State Directly

Incorrect:

form.email = "test@gmail.com";
Enter fullscreen mode Exit fullscreen mode

Correct:

setForm({
 ...form,
 email:"test@gmail.com"
});
Enter fullscreen mode Exit fullscreen mode

4. Too Much Form Logic Inside Component

Large enterprise forms can become difficult to maintain.

Solutions:

  • Custom hooks
  • Form libraries
  • Schema validation

Popular libraries:

  • React Hook Form
  • Formik
  • Zod

Best Practices

  • Use controlled components for most forms.
  • Keep form state organized.
  • Validate before submitting.
  • Show meaningful error messages.
  • Separate validation logic from UI.
  • Reuse common form components.

Key Takeaways

Today, we learned:

✅ React forms are commonly managed using controlled components.
✅ State becomes the single source of truth for form values.
value and onChange work together to control inputs.
preventDefault() prevents browser refresh on submission.
✅ Multiple inputs can be managed using a single state object.
✅ Form validation is an essential part of production applications.


Coming Next 🚀

In Day 13, we will explore:

React Hooks Deep Dive – Understanding useEffect

We will learn:

  • Why useEffect exists
  • Component lifecycle with useEffect
  • Dependency arrays
  • API calls
  • Cleanup functions
  • Common mistakes
  • Real-world examples

useEffect is one of the most important Hooks in React and is heavily used in production applications.

Happy Coding! 🚀

Top comments (0)