Controlled vs Uncontrolled

Choose between React-driven state and letting the DOM hold the value.

Syntax// controlled: value + onChange // uncontrolled: defaultValue + ref

There are two ways to handle form inputs in React.

Controlled

React state is the source of truth. The input's value comes from state and updates on onChange. Best when you need instant validation, formatting, or to react to every keystroke.

Uncontrolled

The DOM keeps the value. You read it when needed via a ref and set an initial value with defaultValue. Simpler for basic forms and file inputs.

Example

Example Β· javascript
import { useRef } from 'react';

function UncontrolledForm() {
  const nameRef = useRef(null);
  function handleSubmit(e) {
    e.preventDefault();
    console.log(nameRef.current.value);
  }
  return (
    <form onSubmit={handleSubmit}>
      <input ref={nameRef} defaultValue="Ada" />
      <button>Submit</button>
    </form>
  );
}

When to use it

  • A live username-availability checker uses a controlled input so the component can read the current value synchronously on every keystroke to debounce API calls.
  • A file-upload widget uses an uncontrolled input with a ref because file inputs cannot be made fully controlled in React and only need their value read on submit.
  • A third-party date picker library manages its own internal state, so the parent treats it as uncontrolled and reads the selected date through a ref on form submit.

More examples

Controlled input

React owns the input's value through state; every keystroke updates state and re-renders the input.

Example Β· jsx
import { useState } from 'react';

function ControlledEmail() {
  const [email, setEmail] = useState('');
  return (
    <input
      type="email"
      value={email}
      onChange={e => setEmail(e.target.value)}
    />
  );
}

Uncontrolled input with ref

Lets the DOM own the value (defaultValue, not value) and reads it through a ref only on form submission.

Example Β· jsx
import { useRef } from 'react';

function UncontrolledForm() {
  const nameRef = useRef(null);

  function handleSubmit(e) {
    e.preventDefault();
    console.log(nameRef.current.value);
  }

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

Uncontrolled file input

File inputs must be uncontrolled; the ref reads the selected file object only when the user submits.

Example Β· jsx
import { useRef } from 'react';

function FileUpload({ onUpload }) {
  const fileRef = useRef(null);

  function handleSubmit(e) {
    e.preventDefault();
    const file = fileRef.current.files[0];
    if (file) onUpload(file);
  }

  return (
    <form onSubmit={handleSubmit}>
      <input type="file" ref={fileRef} accept="image/*" />
      <button type="submit">Upload</button>
    </form>
  );
}

Discussion

  • Be the first to comment on this lesson.