Skip to main content

Command Palette

Search for a command to run...

Controlled vs. Uncontrolled Components in React

Exploring How Controlled and Uncontrolled Components Work in React

Updated
3 min read
Controlled vs. Uncontrolled Components in React

In React, the terms controlled and uncontrolled primarily describe how form elements (like <input>, <select>, or <textarea>) handle their internal state.

1. Controlled Components

In a controlled component, the form data is handled by the React component state. React is the "single source of truth".

React state controls the input value. Every keystroke updates state.

How it works: The input's value is bound to a state variable (e.g., via useState). Every time the user types, an onChange handler updates that state, which then re-renders the input with the new value.

Best for:

  • Real-time validation: Checking if a password is long enough as the user types.

  • Conditional UI: Disabling a submit button until all fields are valid.

  • Format enforcement: Automatically formatting a phone number or forcing uppercase.

Downside: Can be verbose (requires more boilerplate code) and may cause performance issues in extremely large forms due to frequent re-renders (Since state will update when change in input).

When to use: When you need instant validation, formatting, or conditional rendering based on input.

Example

import { useState } from 'react';

function LoginForm() {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');

  const handleSubmit = (e) => {
    e.preventDefault();
    // Validate before sending
    if (!email.includes('@')) {
      alert('Invalid email');
      return;
    }
    console.log({ email, password });
  };

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        value={email}
        onChange={(e) => setEmail(e.target.value)}
        placeholder="Email"
      />
      <input
        type="password"
        value={password}
        onChange={(e) => setPassword(e.target.value)}
        placeholder="Password"
      />
      <button type="submit">Login</button>
    </form>
  );
}

2. Uncontrolled Components

In an uncontrolled component, the form data is handled by the DOM itself.

How it works: You use a ref (via useRef) / JavaScript methods to "pull" the value from the DOM element only when you need it (e.g., upon form submission). You can set an initial value using the defaultValue prop.

Best for:

  • Simple forms: When you only need the value once at the end.
  • Non-React integration: When using third-party libraries that directly manipulate the DOM.
  • Large forms: Where reducing re-renders is critical for performance.

One benefit of uncontrolled components is they work seamlessly with browser's built-in features like autoComplete, form validation, and password managers without additional code.

<input 
  ref={emailRef}
  name="email"
  autoComplete="email"
  // ↑ Browser handles everything automatically
/>

Downside: You lose granular control; you cannot easily react to changes in real-time or enforce complex formatting.

When to use: File inputs (must be uncontrolled), simple forms, third-party DOM integrations, performance-critical inputs.

Example

import { useRef } from 'react';

function FileUpload() {
  const fileRef = useRef(null);
  const nameRef = useRef(null);

  const handleSubmit = (e) => {
    e.preventDefault();
    const file = fileRef.current.files[0];
    const name = nameRef.current.value;

    if (!file) {
      alert('Select a file');
      return;
    }

    const formData = new FormData();
    formData.append('file', file);
    formData.append('name', name);

    // Send to API
    console.log('Uploading:', { name, file: file.name });
  };

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

Quick Decision Guide

  • Need live validation/formatting? → Controlled

  • Just need the value on submit? → Uncontrolled

  • File input? → Must be uncontrolled

  • Thousands of inputs? → Consider uncontrolled for performance