React, how to make a checked checkbox editable

By

Learn how to make a React checkbox start checked but still editable by using the defaultChecked attribute instead of checked, which locks the input state.

~~~

To make a checkbox start checked but still editable in React, use the defaultChecked attribute instead of checked. Passing checked without an onChange handler locks the checkbox.

Here’s the full story. I had a checkbox in a React component:

<input name="enable" type="checkbox" />

and I wanted it to be checked by default, yet the user could change its value.

Using

<input name="enable" type="checkbox" checked="checked" />

didn’t work. The checkbox state could not be changed.

Why does checked freeze the checkbox?

In React, passing checked to an input makes it a controlled component. React takes ownership of its state: on every render, the checkbox shows exactly the value you passed.

Since I passed a fixed value and no onChange handler, React re-rendered the checkbox as checked after every click. React even warns you about this in the browser console: it tells you that you provided a checked prop to a form field without an onChange handler.

The fix: defaultChecked

The solution was to use the defaultChecked attribute:

<input name="enable" type="checkbox" defaultChecked={true} />

defaultChecked sets the initial state and then leaves the checkbox alone. The browser handles the clicks, and the user can toggle it freely. This is called an uncontrolled component.

If the checkbox needs to be checked depending if the value was checked in a variable (for example in an editing form when you are getting the actual value from the database) you can use

<input name="enable" type="checkbox" defaultChecked={existing_enable_value} />

When you need the value in state

If your component must react to the checkbox changing, use the controlled version with useState:

const [enabled, setEnabled] = useState(true)

<input
  name="enable"
  type="checkbox"
  checked={enabled}
  onChange={(event) => setEnabled(event.target.checked)}
/>

Now the checkbox is editable, and enabled always holds the current value.

One pitfall with defaultChecked

defaultChecked is only read on the first render. If the variable you pass changes later, the checkbox won’t update to match it.

So if you load the data after the component mounts and need the checkbox to follow it, switch to the controlled version above.

Tagged: React · All topics
~~~

Related posts about react: