How to Create a Form in React

Use React forms when your app needs user input, validation, submissions, or multi-step workflows. The cleanest starting point is a controlled form using useState() and an onSubmit handler.

What you’ll build or solve

You’ll learn how to create a form in React with controlled inputs, state, and submit handling. You’ll also know how to scale the pattern to multiple fields.

When this approach works best

This approach is the right choice when the UI needs predictable input state and easy validation.

Common real-world scenarios include:

  • Login forms
  • Checkout details
  • Search bars
  • Profile editors
  • Feedback forms

This is a bad idea when the form is huge and better handled by a dedicated library like React Hook Form.

Prerequisites

You only need:

  • A React component
  • Basic useState() knowledge
  • Basic JSX knowledge

Step-by-step instructions

Step 1: Create controlled form state

Start with one field in state.

JavaScript

import { useState } from "react";

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

  function handleSubmit(event) {
    event.preventDefault();
    console.log(email);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(event) => setEmail(event.target.value)}
      />
      <button type="submit">Log in</button>
    </form>
  );
}

export default LoginForm;

This keeps the input value fully controlled by React state.

Step 2: Add multiple fields

For multiple inputs, use one state object.

JavaScript

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

Update the changed field dynamically.

JavaScript

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

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

Then connect the fields.

JavaScript

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

This scales well for most common forms.

Step 3: Add submit logic and validation

Basic validation fits naturally inside submit handlers.

JavaScript

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

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

  console.log(formData);
}

What to look for:

  • Controlled inputs use value + onChange
  • Use event.preventDefault() on submit
  • Object state scales better for many fields
  • Great for validation
  • Keep field names aligned with state keys

Examples you can copy

Search form

JavaScript

<input
  value={query}
  onChange={(event) => setQuery(event.target.value)}
/>

Login form object state

JavaScript

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

Submit handler

JavaScript

<form onSubmit={handleSubmit}>

Common mistakes and how to fix them

Mistake 1: Forgetting preventDefault()

What the reader might do:

Submit the form without blocking browser refresh.

Why it breaks: the page reloads and resets the app state.

Corrected approach:

Use event.preventDefault().

Mistake 2: Missing value on controlled inputs

What the reader might do:

Use onChange but no value.

Why it breaks: the field becomes uncontrolled or inconsistent.

Corrected approach:

Always pair both.

Mistake 3: Wrong name attributes in shared handlers

What the reader might do:

Mismatch name="userEmail" with formData.email.

Why it breaks: the wrong key updates.

Corrected approach:

Align field names with state keys.

Troubleshooting

If the page refreshes, add preventDefault().

If typing does not work, confirm value and onChange are both present.

If shared handlers fail, verify input name values.

If the form grows large, consider React Hook Form.

Quick recap

  • Use controlled inputs with state
  • Pair value with onChange
  • Prevent default form refresh
  • Use object state for multiple fields
  • Align name attributes with state keys