Skip to content

React Forms - Controlled vs Uncontrolled Components

Posted on:January 14, 2026 at 10:00 AM

Hey there! đź‘‹

If you’ve built anything interactive on the web, you’ve definitely touched a Form. Login, Register, “Contact Us”—forms are everywhere.

In standard HTML, forms are pretty straightforward. But in React, things get a bit… interesting. You’ll often hear terms like “Controlled” and “Uncontrolled” components thrown around.

Confused? Don’t be. Today, I’m going to explain exactly what they are and which one you should use. Let’s simplify this!

1. Controlled Components (The “React Way”)

In a Controlled Component, React is in charge. The value of the form input is stored in the component’s State (useState).

Every time you type a character, an onChange event fires, updates the state, and React re-renders the input with the new value. It’s a loop.

Here is how it looks:

import { useState } from "react";

const ControlledForm = () => {
  const [name, setName] = useState("");

  const handleSubmit = (e) => {
    e.preventDefault();
    alert(`Hello, ${name}!`);
  };

  return (
    <form onSubmit={handleSubmit} className="p-4 border rounded">
      <label className="block mb-2">Name:</label>
      <input
        type="text"
        value={name} // 1. Value comes from State
        onChange={(e) => setName(e.target.value)} // 2. Change updates State
        className="border p-2 rounded w-full mb-4"
      />
      <button type="submit" className="bg-blue-500 text-white px-4 py-2 rounded">
        Submit
      </button>
    </form>
  );
};

Why use this?

The downside? You write a bit more code. But for complex forms, it’s usually worth it.

2. Uncontrolled Components (The “HTML Way”)

In an Uncontrolled Component, the DOM is in charge. React doesn’t constantly track the value. Instead, when you need the value (like when submitting), you “pull” it from the DOM using a Ref (useRef).

It feels a lot more like traditional HTML/JavaScript.

import { useRef } from "react";

const UncontrolledForm = () => {
  const nameInputRef = useRef(null); // Create a Ref

  const handleSubmit = (e) => {
    e.preventDefault();
    // Read the value directly from the DOM element
    const name = nameInputRef.current.value;
    alert(`Hello, ${name}!`);
  };

  return (
    <form onSubmit={handleSubmit} className="p-4 border rounded">
      <label className="block mb-2">Name:</label>
      <input
        type="text"
        ref={nameInputRef} // Attach the Ref here
        defaultValue="" // Use defaultValue, not value!
        className="border p-2 rounded w-full mb-4"
      />
      <button type="submit" className="bg-green-500 text-white px-4 py-2 rounded">
        Submit
      </button>
    </form>
  );
};

Why use this?

So, Which One Should I Use?

As a general rule of thumb:

  1. Use Controlled Components for most things. It gives you more power and control over the data. If you need validation or dynamic UI updates, this is the way.
  2. Use Uncontrolled Components if you’re building a super simple form (like a quick newsletter signup), need to handle file uploads, or are migrating an old vanilla JS app to React.

Wrapping Up

There is no “wrong” answer, just the right tool for the job.

Master both, and you’ll never fear a form again. Happy coding! 🚀