react: Add some way to specify indeterminate checkboxes

There should be a way do do <input type="checkbox" indeterminate={true} /> or similar – right now the attribute is ignored. Need to figure out how this interacts with checked though.

About this issue

  • Original URL
  • State: closed
  • Created 10 years ago
  • Reactions: 39
  • Comments: 30 (16 by maintainers)

Most upvoted comments

It’d be great if we were able to set indeterminate as react prop.

It seems like we’re not doing it because it’s impossible to support with server rendering, and we’re currently only supporting a subset of attributes/properties that are compatible both with client and server rendering.

If you need it, it is trivial to implement with your own component:

https://codepen.io/gaearon/pen/aLyEmr?editors=0010

class Checkbox extends React.Component {
  componentDidMount() {
    this.el.indeterminate = this.props.indeterminate;
  }

  componentDidUpdate(prevProps) {
    if (prevProps.indeterminate !== this.props.indeterminate) {
      this.el.indeterminate = this.props.indeterminate;
    }
  }

  render() {
    return (
      <input {...this.props} type="checkbox" ref={el => this.el = el} />
    );
  }
}

Checkbox.defaultProps = {
  indeterminate: false,
};

// Usage
ReactDOM.render(
  <Checkbox indeterminate={true} />,
  document.getElementById('root')
);

There might be a few more gotchas (see the thread above) but I hope this shows that it’s easy to achieve with React even without React directly supporting it.

FWIW, I discovered a clean way to do this as follows:

<input type="checkbox" ref={elem => elem && (elem.indeterminate = isIndeterminate)} />

http://codepen.io/anon/pen/LRoLXZ?editors=0010

Maybe we should do checked equal to true, false, or 'indeterminate'? :\ I am clearly an API design genius.

checked should be either true/false

indeterminate should be either true/false

if indeterminate === true and checked state is updated, indeterminate becomes false

http://www.w3.org/TR/2014/WD-html51-20140617/forms.html#checkbox-state-(type=checkbox)

Is this a fine approach, compared the solution @gaearon suggested?

export default function Checkbox(props) {
  const setCheckboxRef = checkbox => {
    if (checkbox) {
      checkbox.indeterminate = props.isIndeterminate;
    }
  };

  return (
    <input
      type="checkbox"
      ref={setCheckboxRef}
    />
  );
}

Checkbox.propTypes = {
  isIndeterminate: PropTypes.bool,
};

Checkbox.defaultProps = {
  isIndeterminate: false
};

React adds declarative layers over a lot of imperative DOM API’s, which is to say just b/c there is an HTML attribute doesn’t actually mean its a declarative API, that and the prop’s are sugar over the js API’s anyway.

Agree that its a bit weird to add in an “attribute”, but that’s the main React API surface for interacting with DOM objects, so if possible i’d be nice to have. It does fall into the “a bit outside the norm” for react but not very far I think. CC also the discussions about adding a declarative focus() api (that’s not autoFocus).

Yes, that should be fine too.

If you have one checkbox that’s checked and one checkbox that’s not checked, put both of them in an indeterminate state then click both of them, the two checkboxes will have opposite checked states in all of the browsers listed above. This means there are still two distinct bits of information, at least in the browser’s implementation.

Can I just point out that there is no indeterminate HTML attribute? Developers have always had to set the status via JS. It seems against React’s nature to patch something that doesn’t actually exist in declarative DOM land?

I have the same issue. Is there are any ability to set indeterminate property for the checkbox within React?

Found the solution:

  componentDidMount: ->
    $('input', this.getDOMNode()).prop({
      indeterminate: true,
      checked: false
    })

or just a react version:

  componentDidMount: ->
    checkbox = this.refs.checkbox.getDOMNode()
    checkbox.indeterminate = true
    checkbox.checked = false

But what are the drawbacks, except the jquery/zepto are used in this example?

Isn’t in that case an element will be always be rerendered?

@kolodny I wouldn’t really call that clean. Making a HOC would be a better approach. You’re hijacking refs to make a side effect.

@cema-sp My recommendation in the mean time is to just create a CheckboxInput component that does that internally the way you want it. If React ends up implementing this then the implementation will end up being identical anyway, but part of the native input wrapper.

The correct combination of indeterminate and checked. (eg indeterminate=true and checked=true is impossible, indeterminate=true and checked=false is ok edit, even when you explicitly say checked=false)