How to Set the Checked Property for a React Checkbox: Controlled vs Uncontrolled Patterns

To set the checked property for a React checkbox, bind the checked attribute to component state and provide an onChange handler for controlled components, or use defaultChecked for uncontrolled components.

In the facebook/react repository, checkbox handling is implemented in the ReactDOMInput module, which synchronizes the DOM checked property with your component’s props. Understanding how React manages this synchronization helps you implement robust form controls without unexpected behavior.

Understanding the Checked Property in React

React treats checkboxes as either controlled or uncontrolled components. This distinction determines how you set and update the checked property.

Controlled vs Uncontrolled Checkboxes

A controlled checkbox receives its checked value from React state and notifies changes via onChange. An uncontrolled checkbox manages its own DOM state, similar to standard HTML, using defaultChecked for the initial value.

According to the React source code in packages/react-dom/src/client/ReactDOMInput.js, React tracks the "current" checked value and compares it against the "dirty" value coming from the element. It updates the DOM only when these values differ, ensuring efficient synchronization.

React Warning for Missing Handlers

When you provide a checked prop without an onChange handler (or readOnly attribute), React issues a warning. This occurs because the checkbox becomes read-only from the user’s perspective—React controls the value, but provides no mechanism to update the state driving that value.

Setting the Checked Property in Controlled Components

For controlled checkboxes, always pair the checked prop with an onChange handler.

Basic Controlled Checkbox

import { useState } from 'react';

function AgreeCheckbox() {
  const [agreed, setAgreed] = useState(false);

  const handleChange = (e) => {
    setAgreed(e.target.checked);
  };

  return (
    <label>
      <input
        type="checkbox"
        checked={agreed}
        onChange={handleChange}
      />
      I agree to the terms
    </label>
  );
}

In this example, checked={agreed} binds the input to React state. When the user clicks the checkbox, handleChange updates the state, which triggers a re-render with the new checked value.

Read-Only Controlled Checkbox

If you need to display a checkbox that users cannot modify, use the readOnly attribute to suppress React’s warning:

function ReadOnlyCheckbox() {
  return (
    <input
      type="checkbox"
      checked={true}
      readOnly
    />
  );
}

The readOnly prop signals to React that this controlled component intentionally prevents user interaction.

Setting the Checked Property in Uncontrolled Components

For uncontrolled checkboxes, use defaultChecked to set the initial state without React state management.

function UncontrolledCheckbox() {
  return (
    <input
      type="checkbox"
      defaultChecked={true}
    />
  );
}

defaultChecked only affects the initial render. Afterward, the checkbox behaves like a standard HTML input, maintaining its own internal state. This approach is useful when you only need to read the value during form submission using a ref, rather than responding to every change.

Advanced Pattern: Select All Checkbox

A common use case involves a "Select All" checkbox that controls multiple items. This demonstrates aggregate state management with the checked property.

import { useState } from 'react';

function TodoList() {
  const [items, setItems] = useState([
    {id: 1, text: 'Buy milk', done: false},
    {id: 2, text: 'Walk dog', done: true},
  ]);

  const toggleAll = (e) => {
    const checked = e.target.checked;
    setItems(items.map(item => ({...item, done: checked})));
  };

  const toggleItem = (id) => (e) => {
    const checked = e.target.checked;
    setItems(items.map(item => item.id === id ? {...item, done: checked} : item));
  };

  const allChecked = items.every(item => item.done);

  return (
    <div>
      <label>
        <input
          type="checkbox"
          checked={allChecked}
          onChange={toggleAll}
        />
        Select all
      </label>
      <ul>
        {items.map(item => (
          <li key={item.id}>
            <label>
              <input
                type="checkbox"
                checked={item.done}
                onChange={toggleItem(item.id)}
              />
              {item.text}
            </label>
          </li>
        ))}
      </ul>
    </div>
  );
}

The "Select all" checkbox uses checked={allChecked} where allChecked derives from the array state. Clicking it updates all items simultaneously, while individual checkboxes update specific entries.

Key Implementation Files in React Source

Understanding how React handles the checked property internally helps debug edge cases. The facebook/react repository contains the following relevant files:

These files demonstrate that React treats the checked property as a controlled attribute requiring explicit state management, with safeguards to prevent accidental read-only components.

Summary

  • Use checked with onChange to create controlled checkboxes that React manages fully.
  • Use defaultChecked for uncontrolled checkboxes where React only sets the initial value.
  • Add readOnly when displaying a controlled checkbox that users cannot modify to suppress React warnings.
  • Access e.target.checked in event handlers to read the new boolean state.
  • The synchronization logic resides in ReactDOMInput.js, which optimizes DOM updates by comparing current and incoming values.

Frequently Asked Questions

What is the difference between checked and defaultChecked in React?

checked creates a controlled component where React manages the state and updates the DOM based on the prop value. defaultChecked sets the initial checked state for an uncontrolled component, after which the browser manages the state internally. Use checked when you need to respond to changes or derive values from the checkbox state; use defaultChecked when you only need the value at form submission time.

Why does React warn me when I set checked without onChange?

React issues a warning because providing a checked prop without an onChange handler (or readOnly attribute) creates a read-only controlled component. The user sees a checkbox they cannot interact with because React always resets the DOM to match the prop value, but no handler exists to update that prop value. Either add an onChange handler to update state, or add readOnly to indicate the intentional read-only behavior.

How do I set a checkbox to checked by default in React?

For uncontrolled checkboxes, use the defaultChecked prop set to true. For controlled checkboxes, initialize your state variable to true and pass it to the checked prop. For example: const [isChecked, setIsChecked] = useState(true); then checked={isChecked}. Avoid mixing both approaches on the same input, as React will warn about switching between controlled and uncontrolled modes.

Can I use the checked property without React state?

Yes, but this creates an uncontrolled component using defaultChecked rather than checked. The checked prop specifically requires state management because React treats it as a controlled attribute. If you attempt to use checked with a static value (like checked={true}) without state or readOnly, React will warn you. For truly uncontrolled behavior where the DOM maintains its own state, always use defaultChecked.

Have a question about this repo?

These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:

Share the following with your agent to get started:
curl -s https://instagit.com/install.md

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client