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:
-
packages/react-dom/src/client/ReactDOMInput.js– Implements the DOM-level handling of<input>elements, including thecheckedproperty synchronization logic that compares "current" and "dirty" values before updating the DOM. -
packages/react-dom/src/__tests__/ReactDOMInput-test.js– Contains the test suite covering checkbox behavior, including warnings for missingonChangehandlers and verification ofchecked/defaultCheckedhandling. -
packages/shared/ReactFeatureFlags.js– Contains feature flags that can control the synchronization behavior of form attributes likecheckedandvalue.
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
checkedwithonChangeto create controlled checkboxes that React manages fully. - Use
defaultCheckedfor uncontrolled checkboxes where React only sets the initial value. - Add
readOnlywhen displaying a controlled checkbox that users cannot modify to suppress React warnings. - Access
e.target.checkedin 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:
curl -s https://instagit.com/install.md