🚀 LEVEL UP TO SENIOR:Unlock 500+ Advanced Practical Challenges & Exercises.
🎓 COURSERA PARTNER:Earn professional Google, Meta, and IBM certificates to supercharge your resume.
REFERENCEreact

react Documentation

LOADING ENGINE...

Controlled vs Uncontrolled

AI & DATA SCIENCE // controlled-vs-uncontrolled

A controlled input's value is driven entirely by React state, while an uncontrolled input manages its own value internally in the DOM, typically read via a ref only when needed.

Syntax

// Controlled: <input value={value} onChange={handleChange} />
// Uncontrolled: <input ref={inputRef} defaultValue="initial" />

Deep Dive Course

A controlled input has React as the single source of truth for its current value, via the value prop, updated through an onChange handler that keeps state in sync with every keystroke, letting the component always know, validate, or react to the current value in real time. An uncontrolled input instead lets the DOM manage its own value internally, the way a plain HTML form traditionally works, with React only reading that value on demand via a ref, typically at the moment of form submission rather than on every keystroke — defaultValue, not value, sets an uncontrolled input's initial content without making it controlled.

1Understanding Controlled vs Uncontrolled

A controlled input has React as the single source of truth for its current value, via the value prop, updated through an onChange handler that keeps state in sync with every keystroke, letting the component always know, validate, or react to the current value in real time. An uncontrolled input instead lets the DOM manage its own value internally, the way a plain HTML form traditionally works, with React only reading that value on demand via a ref, typically at the moment of form submission rather than on every keystroke — defaultValue, not value, sets an uncontrolled input's initial content without making it controlled.

💡

Mixing value and defaultValue on the same input, or switching an input between having and not having a value prop across renders, produces confusing behavior and React warnings — commit to either the controlled or uncontrolled pattern for a given input and stick with it consistently.

editor.html
import { useState } from 'react';

function ControlledInput() {
  const [value, setValue] = useState('');
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}
localhost:3000

2Practical Example

Here is a real-world application of Controlled vs Uncontrolled showing how it is used in production React code.

editor.html
import { useRef } from 'react';

function UncontrolledInput() {
  const inputRef = useRef(null);
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Value at submission:', inputRef.current.value);
  };
  return (
    <form onSubmit={handleSubmit}>
      <input ref={inputRef} defaultValue="initial" />
      <button type="submit">Submit</button>
    </form>
  );
}
localhost:3000

3Best Practices

Follow these guidelines when working with Controlled vs Uncontrolled:

1. Use controlled inputs by default, especially when you need real-time validation, conditional UI, or to know the current value before actual form submission

2. Use uncontrolled inputs, reading their value via a ref only at submission time, for simpler forms with no per-keystroke needs, or when integrating with non-React code expecting to manage its own input state

3. Use defaultValue, not value, to set an uncontrolled input's starting content, keeping the two patterns clearly separated rather than mixed on the same element

⚠️

Tip: Mixing value and defaultValue on the same input, or switching an input between having and not having a value prop across renders, produces confusing behavior and React warnings — commit to either the controlled or uncontrolled pattern for a given input and stick with it consistently.

editor.html
import { useState } from 'react';

function ControlledInput() {
  const [value, setValue] = useState('');
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}
localhost:3000

Examples

Example 01Basic Usage
import { useState } from 'react';

function ControlledInput() {
  const [value, setValue] = useState('');
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}
Example 02Advanced Example
import { useRef } from 'react';

function UncontrolledInput() {
  const inputRef = useRef(null);
  const handleSubmit = (e) => {
    e.preventDefault();
    console.log('Value at submission:', inputRef.current.value);
  };
  return (
    <form onSubmit={handleSubmit}>
      <input ref={inputRef} defaultValue="initial" />
      <button type="submit">Submit</button>
    </form>
  );
}

Best Practices

  • Use controlled inputs by default, especially when you need real-time validation, conditional UI, or to know the current value before actual form submission
  • Use uncontrolled inputs, reading their value via a ref only at submission time, for simpler forms with no per-keystroke needs, or when integrating with non-React code expecting to manage its own input state
  • Use defaultValue, not value, to set an uncontrolled input's starting content, keeping the two patterns clearly separated rather than mixed on the same element

Interview Question

Why can't an uncontrolled input easily support real-time validation, like showing an error message as the user types, the way a controlled input can?

Hint: Think about when React actually becomes aware of the input's current value in each approach.

With an uncontrolled input, React has no ongoing awareness of the input's current value at all, the DOM manages it entirely internally, and React only finds out what that value currently is at the specific moment something explicitly reads it through a ref, typically triggered once, at form submission. Real-time validation fundamentally requires re-rendering some part of the UI, like an error message, in direct response to the value changing on every keystroke, which requires React to actually know about each new value as it happens, not just once at the end. A controlled input's onChange handler fires on every keystroke and updates state immediately, giving the component a live, continuously updated value it can validate and react to on every single change, which is precisely the capability an uncontrolled input, only exposing its value on-demand via a ref, doesn't provide without additional workarounds like manually attaching a native event listener.

Exercises

MediumPractice using Controlled vs Uncontrolled in a real scenario.
View Solution
import { useState } from 'react';

function ControlledInput() {
  const [value, setValue] = useState('');
  return <input value={value} onChange={(e) => setValue(e.target.value)} />;
}

Frequently Asked Questions

Why can't an uncontrolled input easily support real-time validation, like showing an error message as the user types, the way a controlled input can?

With an uncontrolled input, React has no ongoing awareness of the input's current value at all, the DOM manages it entirely internally, and React only finds out what that value currently is at the specific moment something explicitly reads it through a ref, typically triggered once, at form submission. Real-time validation fundamentally requires re-rendering some part of the UI, like an error message, in direct response to the value changing on every keystroke, which requires React to actually know about each new value as it happens, not just once at the end. A controlled input's onChange handler fires on every keystroke and updates state immediately, giving the component a live, continuously updated value it can validate and react to on every single change, which is precisely the capability an uncontrolled input, only exposing its value on-demand via a ref, doesn't provide without additional workarounds like manually attaching a native event listener.

Related Functions

usestate-in-formsform-handlinguseref