In the following React class I have a checkbox within a div container. I want a click on the container to toggle the checkbox. I also think I need to bind the onChange of the checkbox input itself, to handle things like when the user is tab/spacing to toggle the state of the checkbox (I also get a warning from React if I don't specify an onChange because this is a controlled component).
My problem is that both of the event handlers fire when I click the checkbox itself, so the state of the checkbox doesn't actually change. I have tried e.preventDefault and e.stopPropagation in handleCheckboxChange but neither seems to do anything.
export default class Item extends React.Component{
constructor(){
super();
this.state={
IsSelected: false
}
}
render(){
return (
<div className="item">
<div className="checkbox-container" onClick={this.handleContainerClick.bind(this)}>
<input type="checkbox" checked={this.state.IsSelected} onChange={this.handleCheckboxChange.bind(this)} />
</div>
</div>
);
}
handleCheckboxChange(e){
this.setState({
IsSelected: !this.state.IsSelected
});
}
handleContainerClick(){
this.setState({
IsSelected: !this.state.IsSelected
}); }
}
If you want the containing <div>
to be in "control" of the checkbox's value, then don't put any handler on the checkbox itself. React will make sure the container will receive the childs click
events.
var CheckboxInClickableBox = React.createClass({
getInitialState: function () {
return {
checked: false
};
},
render: function () {
return (
<div onClick={this.onClick}>
<span>{"Checked: " + this.state.checked}</span>
<br />
<input type="checkbox" checked={this.state.checked} />
</div>
);
},
onClick: function () {
this.setState({
checked: !this.state.checked
});
}
});
Example on JSBin - clicking anywhere in the green box will trigger a toggle.
Also, HTML dictates that a <label>
with a for="pie"
attribute will pass click
events to any <input id="pie">
. This can appear to "break" your checkbox when using the method above - eg:
render: function () {
return (
<div onClick={this.onClick}>
<label htmlFor="pie">{"Checked: " + this.state.checked}</label>
<br />
<input id="pie" type="checkbox" checked={this.state.checked} />
</div>
);
}
Clicking the <label>
will behave as if there were 2 click events:
click
event bubbling from the <label>
to the <div>
and triggering our onClick
handler<label>
"delegating" its click to the <input>
element, due to the for
attribute (htmlFor
in React), which then bubbles up and hits our onClick
handlerExample on JSBin - clicking anywhere in the box except the <label>
will trigger a toggle. Clicking the <label>
will trigger 2 toggles.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With