Popular Searches
Popular Course Categories
Popular Courses

Controlled and Uncontrolled Patterns

Controlled and Uncontrolled Patterns

Advanced React Patterns and Features

Controlled and Uncontrolled Patterns in React JS

Controlled and Uncontrolled Patterns are two approaches to managing component data and user input in React. Controlled components receive their important values through props, usually React state, while uncontrolled components manage certain values internally or through the DOM.

These patterns are commonly used in forms, text inputs, checkboxes, dropdowns, search fields, and reusable UI components.

Course Links: JustAcademy React JS Training Course | Register for React JS Course Demo


1. What Are Controlled Components?

A controlled component is a component whose important value is controlled by its parent through props. For form fields, React state typically stores the current value, and an event handler updates that state when the user interacts with the field.

Whenever the state changes, React renders the input with the updated value.

Example: Controlled Input

import { useState } from "react";

function ControlledInput() {
  const [name, setName] = useState("");

  return (
    <div>
      <label htmlFor="name">Enter your name:</label>
      <input
        id="name"
        type="text"
        value={name}
        onChange={(event) => setName(event.target.value)}
      />
      <p>Your name is: {name}</p>
    </div>
  );
}

export default ControlledInput;

How It Works

  • useState("") creates a state variable to store the input value.
  • value={name} makes the input's displayed value follow React state.
  • onChange handles changes made by the user.
  • setName(event.target.value) updates the state immediately.
  • The paragraph displays the current name as the user types.

Important: A controlled text input should receive a string value throughout its lifetime. Use an empty string as the initial value if no text has been entered yet.


2. What Are Uncontrolled Components?

An uncontrolled component manages its current form value primarily through the DOM rather than having React state dictate the value on every render. React can provide an initial value using defaultValue or an initial checkbox state using defaultChecked.

You can read the current value when needed, commonly through a React ref or the submitted form data.

Example: Uncontrolled Input Using useRef

import { useRef } from "react";

function UncontrolledInput() {
  const nameRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();
    alert("Your name is: " + nameRef.current.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="name">Enter your name:</label>
      <input
        id="name"
        type="text"
        ref={nameRef}
        defaultValue=""
      />
      <button type="submit">Submit</button>
    </form>
  );
}

export default UncontrolledInput;

How It Works

  • useRef(null) creates a ref to access the input DOM element.
  • ref={nameRef} connects the ref to the input.
  • defaultValue sets the initial input value.
  • nameRef.current.value reads the current value when the form is submitted.
  • The input can change without React state being updated on every keystroke.

3. Controlled vs. Uncontrolled Components

Feature Controlled Uncontrolled
Value management Driven by props, commonly backed by React state. Current form value is primarily managed by the DOM.
Common props value or checked defaultValue or defaultChecked
Change handling Usually uses onChange to update state. Can read the value through a ref or form submission.
Access to current value Available directly from state. Read from the DOM or submitted form data.
Validation while typing Easy to implement using state. Requires reading the DOM value or adding event handlers.
Programmatic updates Update the state that controls the value. Usually require DOM access or another form-handling approach.
Code complexity Often requires more state and event-handling code. Can be simpler for basic forms.
Best use cases Dynamic forms, live validation, conditional UI. Simple forms, basic data collection, file inputs.

4. Controlled Text Input

In a controlled text input, React state determines the current text. The onChange handler synchronously updates the state to match the user's input.

import { useState } from "react";

function EmailInput() {
  const [email, setEmail] = useState("");

  return (
    <div>
      <label htmlFor="email">Email:</label>
      <input
        id="email"
        type="email"
        value={email}
        onChange={(event) => setEmail(event.target.value)}
      />
      <p>Entered email: {email}</p>
    </div>
  );
}

export default EmailInput;

This approach is useful when you need to display, validate, filter, or transform input data as the user types.


5. Uncontrolled Text Input

An uncontrolled input can use defaultValue to set its initial text. React does not force its current value to match a state variable on each render.

import { useRef } from "react";

function SearchForm() {
  const searchRef = useRef(null);

  function handleSearch(event) {
    event.preventDefault();
    const searchText = searchRef.current.value;
    alert("Searching for: " + searchText);
  }

  return (
    <form onSubmit={handleSearch}>
      <input
        type="search"
        name="search"
        placeholder="Search here"
        defaultValue=""
        ref={searchRef}
      />
      <button type="submit">Search</button>
    </form>
  );
}

export default SearchForm;

Here, the value is read only when the form is submitted. The component does not need React state to track every keystroke.


6. Controlled Checkboxes

A controlled checkbox uses the checked prop rather than value to represent whether it is selected.

import { useState } from "react";

function TermsCheckbox() {
  const [accepted, setAccepted] = useState(false);

  return (
    <div>
      <label>
        <input
          type="checkbox"
          checked={accepted}
          onChange={(event) => setAccepted(event.target.checked)}
        />
        I accept the terms and conditions
      </label>
      <p>Status: {accepted ? "Accepted" : "Not accepted"}</p>
    </div>
  );
}

export default TermsCheckbox;

For checkboxes, use event.target.checked to retrieve the selected state.


7. Uncontrolled Checkboxes

An uncontrolled checkbox can use defaultChecked to specify its initial selection. Its current state can be read using a ref.

import { useRef } from "react";

function NewsletterForm() {
  const newsletterRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();
    alert(
      newsletterRef.current.checked
        ? "Newsletter selected"
        : "Newsletter not selected"
    );
  }

  return (
    <form onSubmit={handleSubmit}>
      <label>
        <input
          type="checkbox"
          ref={newsletterRef}
          defaultChecked={false}
        />
        Subscribe to newsletter
      </label>
      <button type="submit">Submit</button>
    </form>
  );
}

export default NewsletterForm;

8. Controlled Dropdown Using Select

A controlled dropdown uses React state to track the currently selected option.

import { useState } from "react";

function CountrySelect() {
  const [country, setCountry] = useState("India");

  return (
    <div>
      <label htmlFor="country">Choose a country:</label>
      <select
        id="country"
        value={country}
        onChange={(event) => setCountry(event.target.value)}
      >
        <option value="India">India</option>
        <option value="USA">USA</option>
        <option value="UK">UK</option>
      </select>
      <p>Selected country: {country}</p>
    </div>
  );
}

export default CountrySelect;

When the user selects another country, React state updates and the displayed selection follows that state.


9. Uncontrolled Dropdown Using Select

An uncontrolled dropdown can use defaultValue for its initial selection. Its current selection can be accessed using a ref.

import { useRef } from "react";

function UncontrolledCountrySelect() {
  const countryRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();
    alert("Selected country: " + countryRef.current.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <select ref={countryRef} defaultValue="India">
        <option value="India">India</option>
        <option value="USA">USA</option>
        <option value="UK">UK</option>
      </select>
      <button type="submit">Submit</button>
    </form>
  );
}

export default UncontrolledCountrySelect;

10. Controlled Textarea

A controlled textarea uses the value prop and an onChange handler to maintain its text in React state.

import { useState } from "react";

function FeedbackForm() {
  const [feedback, setFeedback] = useState("");

  return (
    <div>
      <label htmlFor="feedback">Your feedback:</label>
      <textarea
        id="feedback"
        value={feedback}
        onChange={(event) => setFeedback(event.target.value)}
        placeholder="Enter your feedback"
      />
      <p>Characters: {feedback.length}</p>
    </div>
  );
}

export default FeedbackForm;

Controlled textareas are useful for character counters, live previews, validation, and dynamic forms.


11. Uncontrolled Textarea

An uncontrolled textarea uses defaultValue for its initial text and a ref to retrieve the current text when needed.

import { useRef } from "react";

function MessageForm() {
  const messageRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();
    alert("Message: " + messageRef.current.value);
  }

  return (
    <form onSubmit={handleSubmit}>
      <textarea
        ref={messageRef}
        name="message"
        defaultValue=""
        placeholder="Write your message"
      />
      <button type="submit">Send</button>
    </form>
  );
}

export default MessageForm;

12. Controlled vs. Uncontrolled Forms

Controlled forms are useful when the interface needs to react to changes immediately. Uncontrolled forms can be suitable when the application only needs the entered values at submission time.

Controlled Form Example

import { useState } from "react";

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

  function handleSubmit(event) {
    event.preventDefault();
    console.log({ email, password });
  }

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

export default LoginForm;

Uncontrolled Form Example

import { useRef } from "react";

function SimpleLoginForm() {
  const emailRef = useRef(null);
  const passwordRef = useRef(null);

  function handleSubmit(event) {
    event.preventDefault();

    console.log({
      email: emailRef.current.value,
      password: passwordRef.current.value
    });
  }

  return (
    <form onSubmit={handleSubmit}>
      <input
        type="email"
        ref={emailRef}
        placeholder="Email"
        required
      />
      <input
        type="password"
        ref={passwordRef}
        placeholder="Password"
        required
      />
      <button type="submit">Login</button>
    </form>
  );
}

export default SimpleLoginForm;

Security note: These examples demonstrate input handling only. Real login systems must send credentials securely to a trusted authentication service. Do not log passwords or other sensitive information in production.


13. What Is the Difference Between value and defaultValue?

Prop Meaning Pattern
value Specifies the current value of a text input, textarea, or select. Controlled
defaultValue Specifies the initial value of a form field. Uncontrolled
checked Specifies the current selected state of a checkbox or radio input. Controlled
defaultChecked Specifies the initial selected state of a checkbox or radio input. Uncontrolled

For a controlled field, the value should be updated through the associated state. For an uncontrolled field, changing defaultValue after the initial render does not act as a command to update its current value.


14. What Is the Role of useState and useRef?

Hook Purpose Typical Use
useState Stores data that affects the rendered UI and triggers a render when updated. Controlled inputs, live validation, conditional messages.
useRef Stores a persistent reference without triggering a render when its value changes. Accessing an input DOM element, focusing an input, reading uncontrolled values.

A ref can also store values unrelated to the DOM, so it is not limited to uncontrolled inputs. Choose the hook based on whether changes need to update the UI.


15. File Inputs in React

An is normally uncontrolled because the browser controls the selected file value. Use a ref to access the selected file objects.

import { useRef } from "react";

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

  function handleSubmit(event) {
    event.preventDefault();

    const files = fileRef.current.files;

    if (files.length > 0) {
      console.log("Selected file:", files[0].name);
    }
  }

  return (
    <form onSubmit={handleSubmit}>
      <label htmlFor="document">Choose a file:</label>
      <input id="document" type="file" ref={fileRef} />
      <button type="submit">Upload</button>
    </form>
  );
}

export default FileUpload;

The example reads the selected filename. Uploading the file requires additional logic to send the file to a server.


16. Validation in Controlled and Uncontrolled Patterns

Controlled components make live validation straightforward because the current value is already available in React state.

Example: Live Email Validation

import { useState } from "react";

function EmailValidation() {
  const [email, setEmail] = useState("");

  const isValid = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(email);

  return (
    <div>
      <label htmlFor="email">Email:</label>
      <input
        id="email"
        type="email"
        value={email}
        onChange={(event) => setEmail(event.target.value)}
      />
      {email.length > 0 && (
        <p>{isValid ? "Email format looks valid" : "Enter a valid email"}</p>
      )}
    </div>
  );
}

export default EmailValidation;

This example checks the email format for demonstration purposes. Production applications should combine appropriate client-side validation with server-side validation.


17. Common Mistakes and Solutions

Mistake Why It Happens Solution
Using value without onChange. The field is controlled but its state cannot be updated by normal user input. Add an onChange handler or use readOnly if appropriate.
Using value={undefined} initially. The input may switch from uncontrolled to controlled. Initialize text state with "" or use value={value ?? ""}.
Using value on a checkbox to control selection. Checkbox selection is controlled through the checked state. Use checked and event.target.checked.
Expecting defaultValue to update the current value. It specifies the initial value rather than continuously controlling the field. Use a controlled input when programmatic updates are required.
Reading a ref before it is attached. The DOM element may not yet exist. Read the ref in an event handler after the component mounts.
Updating controlled state asynchronously on every keystroke. The rendered value can lag behind the browser input. Update the state synchronously from the change event.
Using React state for every simple field without a need. It can add unnecessary state and handlers. Consider uncontrolled fields when only the submitted value is needed.

18. Best Practices

  • Use controlled components when you need live validation, conditional rendering, or programmatic updates.
  • Use uncontrolled components when simple DOM-managed input is sufficient.
  • Do not switch a field between controlled and uncontrolled modes during its lifetime.
  • Use strings for controlled text values and booleans for controlled checkbox states.
  • Use event.target.checked for checkbox and radio selection state.
  • Use refs for DOM access, focus management, and reading uncontrolled fields.
  • Give form fields meaningful labels and names.
  • Use appropriate input types and built-in HTML validation where useful.
  • Keep sensitive information out of console logs.
  • Validate important data on the server, even if client-side validation is present.
  • Choose the simplest pattern that meets the application's requirements.

19. Practical Project: Student Registration Form

Create a Student Registration Form that uses both controlled and uncontrolled patterns.

Requirements

  • Create controlled fields for student name, email, and course selection.
  • Create an uncontrolled field for an optional message.
  • Use a controlled checkbox for accepting terms and conditions.
  • Validate required fields before submission.
  • Read the optional message using a ref.
  • Display a success message after valid submission.
  • Reset the form appropriately after submission.
  • Use accessible labels and suitable input types.

Suggested Component Structure

StudentRegistration/
  ├── StudentRegistration.jsx
  ├── StudentRegistration.css
  └── StudentRegistration.test.jsx

Learning Outcomes

  • Understand how React state controls input values.
  • Learn how refs access DOM elements.
  • Compare form submission and validation strategies.
  • Practice combining controlled and uncontrolled fields in one form.

20. Interview Questions and Answers

Q1. What is a controlled component in React?

A controlled component receives its important value through props, commonly from React state, and uses event handlers to update that state.

Q2. What is an uncontrolled component?

An uncontrolled component keeps its current form value primarily in the DOM rather than having React state control it on every render.

Q3. What is the difference between value and defaultValue?

value controls the current value of a form field, whereas defaultValue specifies its initial value.

Q4. Why is useState used with controlled inputs?

useState stores the current value so the application can update the UI, validate input, and respond to user changes.

Q5. Why is useRef used with uncontrolled inputs?

useRef provides access to the DOM element, allowing the current value to be read when required.

Q6. Which approach is better for forms?

Neither approach is always best. Controlled inputs are useful for dynamic behavior and live validation; uncontrolled inputs can be simpler for basic forms.

Q7. Can controlled and uncontrolled fields be used in the same form?

Yes. A form can use both approaches, as long as each individual field consistently follows one approach.

Q8. How do you control a checkbox?

Use the checked prop and update state using event.target.checked.

Q9. Why should a controlled input not start with undefined?

A controlled text input should receive a string consistently. Starting with undefined and later supplying a string can cause an uncontrolled-to-controlled warning.

Q10. Are file inputs controlled in React?

File inputs are normally uncontrolled because the browser manages file selection. Use a ref to access the selected files.

Q11. Does useRef cause a re-render when its value changes?

No. Updating a ref does not trigger a React render.

Q12. What is live validation?

Live validation checks input while the user types or interacts with a field. Controlled components make it convenient because the current value is already in React state.


21. Practice Exercises

  1. Create a controlled username input that displays the current value.
  2. Create an uncontrolled search form that reads the query using a ref.
  3. Build a controlled checkbox for accepting terms and conditions.
  4. Create a controlled dropdown with five course options.
  5. Build a feedback form with a controlled textarea and character counter.
  6. Create a file upload form that reads the selected filename through a ref.
  7. Build a registration form that combines controlled and uncontrolled fields.
  8. Add validation and test the form's success and error states.

22. Quick Revision

  • Controlled: The current value is driven by props, commonly React state.
  • Uncontrolled: The current form value is primarily managed by the DOM.
  • value and checked are used to control current values.
  • defaultValue and defaultChecked specify initial values.
  • useState is useful when changes should update the rendered UI.
  • useRef is useful for accessing DOM elements and reading uncontrolled fields.
  • Controlled components suit dynamic forms; uncontrolled components can simplify basic forms.
  • File inputs are normally uncontrolled.
  • Both patterns can be used together in a form.

23. Official React Documentation


24. Conclusion

Controlled and uncontrolled patterns are important concepts for handling forms and user input in React. Controlled components provide greater control over input values and make live validation and dynamic UI updates easier. Uncontrolled components let the DOM manage current values and can simplify forms that only need data at submission time.

Understanding both patterns helps you select the right approach for each form field and build maintainable React applications.

Learn More: JustAcademy React JS Training Course | Register for React JS Course Demo

whatsapp