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.
https://mdn.mozillademos.org/en-US/docs/Web/CSS/:indeterminate$samples/Example?revision=601267 is fun to play with.
Not impossible to support, but that's annoying.
Sorry, what's annoying?
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)
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?
The drawback is that your are mutating the DOM manually, which kinda sucks. You also want to make sure this happens in the right place for each subsequent render.
You also want to make sure this happens in the right place for each subsequent render.
How to make sure?
And as I understand componentDidMount
happens after virtual DOM is placed in a real DOM. Between rendering to the real DOM and changing the input it may take some time. In some situations browser reflow can be done few times?
Well, on a re-render componentDidMount
will not get called so you also need to do it in componentDidUpdate
to make sure it happens there if needed.
Pulling in my research from #2973 (and reviving this thread):
Chrome, Firefox, Safari, IE and other modern browsers support the notion of a checkbox in an indeterminate state which can be set or cleared using the
indeterminate
property of a checkbox input node. (It cannot be set using attributes.)This state is most commonly used at the top of a list or tree of checkboxes to indicate that some but not all of the checkboxes underneath are checked.
This behavior seems reasonably well-defined in modern Chrome, Firefox, Safari, and IE. If the checkbox's indeterminate property is set, the checkbox renders its indeterminate state regardless of what its checked state is (or if its checked state is programmatically toggled) and clicking on a checkbox clears its indeterminate state.
Unfortunately there is a little bit of inconsistency. In Chrome, Firefox, and Safari clicking an indeterminate checkbox clears the indeterminate state and also toggles the checked state (triggering both a change and click event) while in IE it just clears the indeterminate state and leaves the checked state alone (triggering only a click event).
- Should React support an
indeterminate
prop for checkbox inputs?- Should it be supported for uncontrolled checkboxes (via an
defaultIndeterminate
or similar prop)?- Should clicking an indeterminate checkbox follow the browser's checked-toggling behavior?
[Claims above come from playing with [this jsFiddle](http://jsfiddle.net/3bn73ey5) in Chrome 40, Firefox 35, Safari 7, and IE 11]
Maybe we should do checked
equal to true
, false
, or 'indeterminate'
? :\ I am clearly an API design genius.
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.
Ooh, good find.
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)
This means there are still two distinct bits of information, at least in the browser's implementation.
That I think is critical to maintain in React's support, a checkbox can be indeterminate: checked, or indeterminate: unchecked.
The frustrating problem though is that the checked
change toggles resets indeterminate
as @jlas notes. perhaps some variation of the controlled/uncontrolled pattern would work?
<input type='checkbox'
checked={checked}
defaultIndeterminate={!checked}
/>
<input type='checkbox'
checked={this.state.checked}
indeterminate={this.state.indeterminate}
onChange={({ target: {checked} }) =>
this.setState({ checked, indeterminate: false }) }
/>
The downside to something like that is that it adds a bunch more logic to the DOMInput wrappers, which I know was something folks were trying to make lighter weight
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?
It seems against React's nature to patch something that doesn't actually exist in declarative DOM land?
@yaycmyk Correct. IMHO it's arguable, but server-rendering in a way necessitates it and seems like a hard problem to otherwise decide where to draw the line. It's really weird that there isn't an attribute for it. Interesting.
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
).
Our form components go a bit beyond what normal HTML attributes give you.
@spicyj Huh? Yes they add additional run-time functionality (i.e. controlled), but the initial state of them all is entirely captured by attributes right? Or am I missing something.
Yeah, that's true.
It is a definitely a good idea to add indeterminate
property. Why hasn't it been solved?
I currently use:
if (shoudNotBeChecked) {
this.refs.checkbox.indeterminate = false;
this.refs.checkbox.checked = false;
} else if (shoudBeChecked) {
this.refs.checkbox.indeterminate = false;
this.refs.checkbox.checked = true;
} else {
this.refs.checkbox.indeterminate = true;
}
...
render() {
return (
<input
type="checkbox"
name="Check"
ref="checkbox"
onChange={this.props.onCheck}
/>,
);
}
@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.
FWIW, I discovered a clean way to do this as follows:
<input type="checkbox" ref={elem => elem && (elem.indeterminate = isIndeterminate)} />
@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.
I'm trying to create a HOC but it doesn't seem to work unless I add a 0-ms timeout. Is this expected?
import React, {PropTypes} from 'react';
export default class Checkbox extends React.Component {
static propTypes = {
indeterminate: PropTypes.bool,
checked: PropTypes.bool,
};
componentDidMount() {
this.el.indeterminate = this.props.indeterminate;
this.el.checked = this.props.checked; // fix for IE8
}
componentDidUpdate(prevProps, prevState) {
if(prevProps.indeterminate !== this.props.indeterminate) {
setTimeout(() => {
this.el.indeterminate = this.props.indeterminate;
}, 0);
}
}
render() {
const {indeterminate, ...attrs} = this.props;
return <input ref={el => {this.el = el;}} type="checkbox" {...attrs}/>;
}
}
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.
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
};
Yes, that should be fine too.
Most helpful comment
It'd be great if we were able to set
indeterminate
as react prop.