Uncontrolled Forms

⭐ Interview Importance: MEDIUM
⏱️ Revision Time: 2 min

Uncontrolled Forms

An Uncontrolled Component is a form element that maintains its own internal state, exactly like traditional HTML. React does not track every keystroke or force a value onto the input.

Instead, React only interacts with the form when absolutely necessary—usually when the user clicks “Submit”—by reading the current value directly from the DOM using a ref or the FormData API.

How to use Uncontrolled Components (using Refs)

You use the useRef hook to get direct access to the DOM node, and then read its .value property when the form is submitted.

import { useRef } from 'react';

function UncontrolledForm() {
  // 1. Create a ref
  const nameInputRef = useRef(null);

  const handleSubmit = (event) => {
    event.preventDefault();
    
    // 3. Read the value directly from the DOM node
    const submittedName = nameInputRef.current.value;
    alert(`A name was submitted: ${submittedName}`);
  };

  return (
    <form onSubmit={handleSubmit}>
      <label>
        Name:
        {/* 2. Attach the ref to the input. Notice there is no 'value' or 'onChange' */}
        <input type="text" ref={nameInputRef} />
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

Setting a Default Value

Because you are not passing a value prop (which would turn it into a controlled component), you use the special defaultValue prop if you want the input to start with some initial text.

<input type="text" ref={nameInputRef} defaultValue="Bob" />

The FormData API Approach (Modern)

Instead of creating a useRef for every single input (which gets tedious in large forms), you can use the native browser FormData API. This is often cleaner for uncontrolled forms.

function FormDataExample() {
  const handleSubmit = (event) => {
    event.preventDefault();
    
    // Pass the actual <form> element (event.target) to FormData
    const formData = new FormData(event.target);
    
    // Read the values using the 'name' attributes of the inputs
    const username = formData.get('username');
    const email = formData.get('email');
    
    console.log({ username, email });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input type="text" name="username" placeholder="Username" />
      <input type="email" name="email" placeholder="Email" />
      <button type="submit">Submit</button>
    </form>
  );
}

Why use Uncontrolled Components?

  1. Performance: Because React doesn’t track every keystroke, the component does not re-render when the user types. This is excellent for massive, complex forms where keystroke re-renders cause lag.
  2. Integration: If you are migrating a legacy application to React, or using a third-party non-React UI library, uncontrolled components are often easier to integrate.

Why avoid them?

Uncontrolled components make it very difficult to implement dynamic UI features based on user input. For example, if you want to instantly show a warning message when a password is too short, or disable the submit button until all fields are valid, you should use Controlled Components instead.

Interview Questions

Q: How do you access the value of an “uncontrolled” input?
A: You attach a React useRef to the input element (e.g., <input ref={inputRef} />), and then read inputRef.current.value exactly when you need it (usually only when the form is actually submitted).