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.
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.