Mern Stack

Handling User Forms in React: A Step-by-Step Guide

Ziaul Kabir
••3 min read
Handling User Forms in React: A Step-by-Step Guide

Forms are essential in many web apps for collecting user input. React simplifies form handling using controlled components, ensuring consistent state and UI synchronization. Let’s build a user registration form with input handling, validation, and submission using modern React and hooks.

Why Controlled Components?

Controlled components tie form inputs to component state via useState. This makes validation, updates, and submission logic much easier to manage.

Example: User Registration Form

We'll build a form that collects a user's name, email, and password. It includes basic validation and inline error messages.

The Code

import { useState } from 'react';
function RegistrationForm() {
  const [formData, setFormData] = useState({
    name: '',
    email: '',
    password: '',
  });
  const [errors, setErrors] = useState({});

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

  const validate = () => {
    const newErrors = {};
    if (!formData.name.trim()) newErrors.name = 'Name is required';
    if (!formData.email.includes('@')) newErrors.email = 'Invalid email';
    if (formData.password.length < 6) newErrors.password = 'Password must be at least 6 characters';
    return newErrors;
  };

  const handleSubmit = (e) => {
    e.preventDefault();
    const validationErrors = validate();
    if (Object.keys(validationErrors).length > 0) {
      setErrors(validationErrors);
      return;
    }
    setErrors({});
    console.log('Form submitted:', formData);
    setFormData({ name: '', email: '', password: '' });
  };

  return (
    <form onSubmit={handleSubmit} className="max-w-md mt-4 space-y-4">
      <div>
        <label htmlFor="name">Name:</label>
        <input type="text" id="name" name="name" value={formData.name} onChange={handleChange} className="w-full border p-2 rounded mt-1"/>
        {errors.name && <span className="text-red-500">{errors.name}</span>}
      </div>
      <div>
        <label htmlFor="email">Email:</label>
        <input type="email" id="email" name="email" value={formData.email} onChange={handleChange} className="w-full border p-2 rounded mt-1"/>
        {errors.email && <span className="text-red-500">{errors.email}</span>}
      </div>
      <div>
        <label htmlFor="password">Password:</label>
        <input type="password" id="password" name="password" value={formData.password} onChange={handleChange} className="w-full border p-2 rounded mt-1"/>
        {errors.password && <span className="text-red-500">{errors.password}</span>}
      </div>
      <button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">Register</button>
    </form>
  );
}
export default RegistrationForm;
    

How It Works

  • State Management: We use useState to store formData and errors.
  • The formData state keeps track of input values, ensuring inputs are controlled.
  • Input Handling: The handleChange function updates formData dynamically using the input's name attribute.
  • The spread operator ...formData preserves other fields while updating the changed one.
  • Validation: Checks for empty name, invalid email, and password shorter than 6 characters.
  • Error messages are displayed below the input if validation fails.
  • Form Submission: Prevents default, runs validation, sets errors or logs and clears form.
  • Inputs are bound to formData via value and updated via onChange.

Using the Form

import RegistrationForm from './RegistrationForm';
function App() {
  return (
    <div className="p-4">
      <h1 className="text-2xl font-bold">User Registration</h1>
      <RegistrationForm />
    </div>
  );
}
export default App;
    

Example Behavior

  • Typing "Alice" updates formData.name.
  • Invalid email shows "Invalid email" in red.
  • Valid form submission logs data and clears inputs.

💡 Advanced Tips

  • Form Libraries: Use React Hook Form or Formik for advanced forms.
  • API Integration: Replace console.log with fetch or axios calls.
  • Real-Time Validation: Add debounce logic in handleChange.
  • Accessibility: Use htmlFor in labels and ARIA attributes.
  • Styling: Replace inline styles with Tailwind or CSS modules for a cleaner UI.

Why This Matters

Mastering controlled components in React empowers you to build dynamic, validated, and accessible forms that easily integrate with APIs. This example is a great foundation for more advanced features like multi-step wizards or file uploads.

Written by

Ziaul Kabir

Share:

Comments (0)

No comments yet. Be the first to comment!