Matt Sweetman

Latest articles

Indeterminate checkboxes in React

I've been working in React recently and once again found myself needing an indeterminate checkbox. I previously mentioned how to do this in Angular. Here's a quick recap: the indeterminate checkbox state can't be set via element attributes (eg: <input indeterminate="false">), but it can be set via JavaScript (eg: inputNode.indeterminate = true. In order to do this you need to get hold of the input DOM node and modify it directly.

If you're using React 0.14+ then this is very simple, all you need to do is use the ref callback attribute:

<input
  type="checkbox"
  checked={props.allItemsSelected}
  ref={input => {
    if (input) {
      input.indeterminate = props.someItemsSelected;
    }
  }}
/>

The ref attribute takes a function that gets called whenever the component is mounted and updated. It passes the attached DOM node as the first argument. The callback also gets called during unmounting, in which case the input argument will be undefined, hence the conditional check. The great thing about the ref callback is it can be provided as an anonymous function, meaning you can keep the surrounding component stateless.

(For older versions of React you'll need to use the ref string attribute and create a stateful component to hook into the lifecycle methods.)

Wrapping it up in a component

The ref callback code is so minimal that I haven't wrapped the checkbox into a component in my own project, but if you'd like a reusable component then this should be all you need:

const Checkbox = props => (
  <input
    {...props}
    type="checkbox"
    ref={input => {
      if (input) {
        input.indeterminate = props.indeterminate;
      }
    }}
  />
);

The component ensures that any other props you pass through will be applied to the input element (using spread attributes). You can use it throughout your code like this:

<div>
  <Checkbox checked={props.allItemsSelected} indeterminate={props.someItemsSelected} />
</div>