Skip to content

Uncontrolled Components

Uncontrolled components store input values in the DOM, not React state. You read values via refs or FormData when needed — typically on submit. They reduce re-renders and simplify some integration scenarios.

Let the DOM Hold the Value

Use defaultValue or defaultChecked for initial values, then read the current value from a ref's .current property or through FormData when the user submits.

File inputs are inherently uncontrolled. Third-party widgets that manage their own DOM state may also work better uncontrolled.

function LoginForm() {
  const emailRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    console.log(emailRef.current.value);
  };

  return (
    <form onSubmit={handleSubmit}>
      <input ref={emailRef} defaultValue="" type="email" />
      <button type="submit">Login</button>
    </form>
  );
}

The ref points to the DOM input; read .value when you need it.

Uncontrolled Patterns

// Ref to single input
<input ref={inputRef} defaultValue="initial" />

// FormData on submit
const data = new FormData(e.currentTarget);

// Imperative focus
inputRef.current?.focus();
  • Use defaultValue, not value, for uncontrolled text inputs.
  • Refs do not trigger re-renders when DOM values change.
  • FormData collects all named fields on submit efficiently.
  • React Hook Form uses refs internally for performance.

Uncontrolled Quick Reference

APIs for uncontrolled form handling.

API Purpose
useRef Hold reference to DOM node
defaultValue Initial text input value
defaultChecked Initial checkbox state
FormData Read all fields on submit
ref.current.focus() Imperative DOM focus
File input Always uncontrolled

When Uncontrolled Makes Sense

Simple forms submitted infrequently, file uploads, integrating non-React widgets, or performance-sensitive forms with dozens of fields are good candidates.

  • Simple login forms with submit-only validation.
  • File inputs — cannot be controlled meaningfully.
  • Large forms where re-render per keystroke hurts.
  • Libraries like React Hook Form that use refs under the hood.

Callback Refs

Instead of useRef, a callback ref runs when the node mounts/unmounts. Useful for measuring DOM size or integrating with non-React libraries.

const measureRef = (node) => {
  if (node) console.log(node.getBoundingClientRect());
};
<div ref={measureRef}>Content</div>

Common Mistakes

  • Using value without onChange (read-only frozen input).
  • Expecting UI to update when reading ref without re-render.
  • Overusing uncontrolled to avoid learning controlled patterns.
  • Forgetting to attach ref to the actual input element.

Key Takeaways

  • Uncontrolled inputs store values in the DOM.
  • Read values via refs or FormData on demand.
  • Good for files, simple forms, and performance cases.
  • Use defaultValue/defaultChecked for initial state.

Pro Tip

React Hook Form gives you uncontrolled performance with a controlled-feeling API — a strong default for production forms.