React - Prevent Event Trigger on Parent From Child

JavascriptCssReactjsEventsDom Events

Javascript Problem Overview


I have this scenario, where when parent element is clicked, it flips to show a child element with different colours. Unfortunately, when the user clicks on one of the colours, the 'click' event on parent is also triggered.

How can I stop the event trigger on parent when the child is clicked?

Possible solutions I am wondering:

  1. CSS?
    Append pointer-events : none class to the parent when the child is clicked. However, this would mean that the parent will need to be cleansed of the pointer-events class later.

  2. Using Ref?
    Record the ref of the parent React element & upon click on the child, compare the event.target against the ref? I don't like this because I don't like the global ref.

Thoughts and the better solution would be much appreciated. The question is: How can I stop the event trigger on parent when the child is clicked?

Javascript Solutions


Solution 1 - Javascript

You can use stopPropagation

> stopPropagation - Prevents further propagation of the current event in > the bubbling phase

var App = React.createClass({
  handleParentClick: function (e) { 
    console.log('parent');
  },

  handleChildClick: function (e) {
    e.stopPropagation();
    console.log('child');
  },

  render: function() {
    return <div>
      <p onClick={this.handleParentClick}>
        <span onClick={this.handleChildClick}>Click</span>
      </p>
    </div>;
  }
});

ReactDOM.render(<App />, document.getElementById('root'));

<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/react/15.1.0/react-dom.min.js"></script>
<div id="root"></div>

Solution 2 - Javascript

I had the same issue in React and solved it using the solution bellow:

if(e.currentTarget != e.target ) return;
.......

Solution 3 - Javascript

Another solution is to attach to the event callback on the parent the following:

if(event.target == event.currentTarget){
  event.stopPropagation()
  ....
}

This way you can intercept events, that originated in the attached DOM node and unrelated events are relayed to the next node.

Solution 4 - Javascript

I wanted to invoke function on props but at the same time wanted to stop event propagation from child to parent, here is how its handled

class LabelCancelable extends Component {

  handleChildClick(e) {
    e.stopPropagation()
  }
  closeClicked(e, props) {
    e.stopPropagation();
    props.onCloseClicked()
  }
  
  render() {
    const {displayLabel} = this.props;
    return (
      <span className={ "label-wrapper d-inline-block pr-2 pl-2 mr-2 mb-2" } onClick={ this.handleChildClick }>
          <button type="button" className="close cursor-pointer ml-2 float-right" aria-label="Close"
              onClick={(e) => this.closeClicked(e, this.props) }>
              <span aria-hidden="true">&times;</span>
          </button>
          <span className="label-text fs-12">
            { displayLabel }
          </span>
      </span>
    );
  }
}

export default LabelCancelable;

Solution 5 - Javascript

I had this problem with Material-UI DataGrid and solved it using this:

event.defaultMuiPrevented = true;

e.g:

<DataGrid
  onCellDoubleClick={(params, event) => {
    if (!event.ctrlKey) {
      event.defaultMuiPrevented = true;
    }
  }}
  {...data}
/>

Solution 6 - Javascript

I find this solution the cleanest. Thank you @JohnFash!

onClick={(event) => event.currentTarget == event.target && doSomething(event)}

Here is an attempt at explaining this in more details: when your mouse enters the parent element, the currentTarget is set (event), then when it enters the child element, the target changes. If you don't do the check, the parent's onClick triggers because the mouseleave event hasn't triggered.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionKayoteView Question on Stackoverflow
Solution 1 - JavascriptOleksandr T.View Answer on Stackoverflow
Solution 2 - JavascriptJohn FashView Answer on Stackoverflow
Solution 3 - JavascriptDanielView Answer on Stackoverflow
Solution 4 - JavascriptMayur NandaneView Answer on Stackoverflow
Solution 5 - JavascriptGifford N.View Answer on Stackoverflow
Solution 6 - JavascriptSaif EhsanView Answer on Stackoverflow