Ownership Violations

Inputs must have a single ownership model for their whole lifetime. Mixing value and defaultValue breaks that invariant and produces warnings, subtle bugs, and confusing UX.

Break the invariant: ownership violation

Minimal interaction first. Flip ownership once and observe how the system state changes. Then read the explanation and compare correct vs buggy code.

Do this once: toggle Make it controlled. The page will simulate the missing value automatically.

Input under test

Input
Mode: uncontrolled
rawValue: "seed"
Why this breaks
The invariant is: single ownership for lifetime. Controlled inputs must always receive a defined value. If the value becomes undefined, React may treat the input as uncontrolled. Once the same DOM node flips ownership, behavior becomes non-deterministic.

Detected issue

Status: READY
Mode changed: — · Flips: 0
Toggle once to reproduce.

Reference (correct mental model)

Uncontrolled (correct)

Uses defaultValue. React does not own the value after mount.

<input defaultValue="seed" />

Controlled (correct)

Uses value. React owns the value for the component lifetime (and you handle onChange if editable).

Controlled (correct): value must never be undefined

<input value={value ?? ""} onChange={...} />

Fix

No visual preview needed

In uncontrolled mode, the fix is conceptual: don’t mix value with defaultValue. If you need to control the value, switch fully to controlled mode instead.

Buggy

// Buggy (uncontrolled) <input defaultValue="seed" value={value} />

Correct

// Correct (uncontrolled) <input defaultValue="seed" />

Key takeaways

  • The invariant: single ownership for lifetime (controlled or uncontrolled).
  • Controlled inputs must keep value defined (often value ?? "").
  • Uncontrolled inputs use defaultValue; don’t mix it with value on the same DOM node.

Approach & tradeoffs

Approach

  • Decide ownership first: controlled vs uncontrolled.
  • Enforce invariants: controlled = always string; uncontrolled = defaultValue only.
  • Keep rerenders cheap if you choose controlled (avoid large trees rerendering per keystroke).

Tradeoffs

  • Controlled inputs can cause frequent rerenders; optimize expensive subtrees.
  • Uncontrolled inputs reduce React overhead but may need refs for reads on submit.
  • Switching ownership later is costly — treat it like an API decision.
Common pitfall

The most common accidental flip is when a controlled input becomes undefined. Fix the root cause: enforce value ?? "".