-
Notifications
You must be signed in to change notification settings - Fork 47k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Add some way to specify indeterminate checkboxes #1798
Comments
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 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. |
How to make sure? |
Well, on a re-render |
Pulling in my research from #2973 (and reviving this thread):
|
Maybe we should do |
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. |
if http://www.w3.org/TR/2014/WD-html51-20140617/forms.html#checkbox-state-(type=checkbox) |
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 <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 |
@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 |
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 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 |
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. |
@gaearon is this possible with RSC? |
Since there is no indeterminate attribute in HTML it’s not possible to make an indeterminate checkbox that appears correctly before any JS is run. However with RSC you can still make a client component that sets the indeterminate property upon mount and render it from a server component. |
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 withchecked
though.The text was updated successfully, but these errors were encountered: