← Back to Chapters

Controlled vs Uncontrolled Components

⚛️ Controlled vs Uncontrolled Components

? Quick Overview

In React, form elements such as <input>, <textarea>, and <select> can be managed in two main ways: controlled and uncontrolled components.

The key difference is who controls the form data — React’s state or the browser’s DOM.

? Goal: Understand when to use controlled vs uncontrolled form components.

? Key Concepts

  • Controlled Component: Form data is stored in React state and updated via event handlers.
  • Uncontrolled Component: Form data is stored in the DOM and accessed using refs.
  • onChange: Used in controlled components to sync user input with state.
  • useRef: Used in uncontrolled components to directly read values from DOM elements.

? Controlled Components

A controlled component is one where form data is handled by React through component state. The input value is tied to a state variable, and any change updates the state.

? View Code Example (Controlled Input)
// Controlled component: React state is the single source of truth
import { useState } from "react";
function ControlledInput() {
const [name, setName] = useState("");
function handleChange(e) {
setName(e.target.value);
}
function handleSubmit(e) {
e.preventDefault();
alert(`Hello, ${name}!`);
}
return (
<form onSubmit={handleSubmit}>
<input
type="text"
value={name}
onChange={handleChange}
placeholder="Enter your name"
/>
<button type="submit">Submit</button>
</form>
);
}

? Explanation

  • name is stored in React state using useState("").
  • value={name} makes the input fully controlled by React.
  • onChange updates the state on every keystroke.
  • On form submit, the latest state value is used to show the greeting.

? Uncontrolled Components

An uncontrolled component keeps the form data inside the DOM instead of React’s state. You access values using refs instead of state.

? View Code Example (Uncontrolled Input)
// Uncontrolled component: value is read directly from the DOM via a ref
import { useRef } from "react";
function UncontrolledInput() {
const inputRef = useRef();
function handleSubmit(e) {
e.preventDefault();
alert(`Hello, ${inputRef.current.value}!`);
}
return (
<form onSubmit={handleSubmit}>
<input type="text" ref={inputRef} placeholder="Enter your name" />
<button type="submit">Submit</button>
</form>
);
}

? Explanation

  • useRef() creates a ref object attached to the input.
  • The input’s value is not stored in React state.
  • On submit, inputRef.current.value reads the value directly from the DOM.
  • React does not re-render on every keystroke because state is not involved.

? Controlled vs Uncontrolled: Side-by-Side

Aspect Controlled Component Uncontrolled Component
Data Handling Managed by React via state Managed by the DOM
Accessing Value Via state variable Via ref
Validation Easy to validate dynamically while typing Requires manual DOM access or native validation
Re-rendering Re-renders on each input change No re-render on input changes
Best For Complex forms needing validation and dynamic UI Simple or one-time input forms

⚙️ When to Use Which?

  • ✅ Use Controlled Components when form data affects rendering or complex validation logic.
  • ✅ Use Uncontrolled Components for simple forms or when you don’t need real-time validation.
  • ⚠️ Avoid mixing both patterns in the same form unless you have a clear reason.

? Tips & Best Practices

  • Prefer controlled components for predictable behavior and easier validation.
  • Use useRef() when you only need the value once (e.g., on submit) and don’t need reactivity.
  • For large forms, consider libraries like Formik or React Hook Form to manage controlled inputs efficiently.
  • Controlled forms make debugging and testing easier because all data lives in React state.

? Try It Yourself

  1. Create a ControlledLogin component with email and password controlled by state.
  2. Create an UncontrolledLogin version using refs for both inputs.
  3. Add validation to the controlled version (e.g., required fields, basic email format check).
  4. Compare how validation and real-time updates behave in each version.
  5. Decide which approach is more suitable for large, dynamic forms in real projects.

Goal: Practice managing form elements through React’s state vs directly via the DOM using refs, and understand when each approach is most effective.