529

I'm currently using jQuery to make a div clickable and in this div I also have anchors. The problem I'm running into is that when I click on an anchor both click events are firing (for the div and the anchor). How do I prevent the div's onclick event from firing when an anchor is clicked?

Here's the broken code:

JavaScript

var url = $("#clickable a").attr("href");

$("#clickable").click(function() {
    window.location = url;
    return true;
})

HTML

<div id="clickable">
    <!-- Other content. -->
    <a href="http://foo.example">I don't want #clickable to handle this click event.</a>
</div>
0

27 Answers 27

640

Events bubble to the highest point in the DOM at which a click event has been attached. So in your example, even if you didn't have any other explicitly clickable elements in the div, every child element of the div would bubble their click event up the DOM to until the DIV's click event handler catches it.

There are two solutions to this is to check to see who actually originated the event. jQuery passes an eventargs object along with the event:

$("#clickable").click(function(e) {
    var senderElement = e.target;
    // Check if sender is the <div> element e.g.
    // if($(e.target).is("div")) {
    window.location = url;
    return true;
});

You can also attach a click event handler to your links which tell them to stop event bubbling after their own handler executes:

$("#clickable a").click(function(e) {
   // Do something
   e.stopPropagation();
});
11
  • 3
    if you had a bunch of elements you wanted to prevent propagation on, you could find their parent element and head prevent it from bubbling up there too. So rather than intercepting all of the a links in a div let's say for example-- just intercept the click even on the div itself and prevent it from going any higher and you're set.
    – sucitivel
    Commented Nov 9, 2012 at 15:28
  • 40
    Using if( e.target !== this) return; in the parent is better than e.stopPropagation() in the child since you never know if someone else attaches some handler to the children, or if a library must attach a handler to a child (and you don't want to mess with the library code). It's a better separation of concerns. Commented Oct 21, 2016 at 17:01
  • 11
    Putting the if( e.target !== this) return; check in the parent means that if any of the other children of that parent that don't have onClick handlers of their own are clicked, then nothing happens. So it's useless for a situation where you have e.g. a clickable parent div. e.stopPropagation() works fine however.
    – derf26
    Commented Apr 25, 2018 at 16:26
  • 2
    It might be worth noting that stopPropagation() doesn't stop other mouse events from being detected on the parent so a "click" event with stopPropagation wont stop an event attached to the parent with "mouseup" instead. It makes sense and is useful but it had me a little confused for a while
    – wunth
    Commented Jun 26, 2018 at 1:19
  • 1
    one can also use this condition event.currentTarget === event.target it returns false in case event is propagated from child element.
    – mukuljainx
    Commented Jul 3, 2021 at 16:24
152

Use stopPropagation method, see an example:

$("#clickable a").click(function(e) {
   e.stopPropagation();
});

As said by jQuery Docs:

stopPropagation method prevents the event from bubbling up the DOM tree, preventing any parent handlers from being notified of the event.

Keep in mind that it does not prevent others listeners to handle this event(ex. more than one click handler for a button), if it is not the desired effect, you must use stopImmediatePropagation instead.

2
  • Watch out so you dont accidentaly have set the event listeners to be passive Commented Jul 25, 2020 at 20:00
  • 2
    Avoid at all costs the use of Event.stopPropagation(). An application (or third party code) should never stop or prevent an Event to propagate through layers, components. Rather check for Event.target.closest("selector") matches and act accordingly. Example Commented Dec 15, 2022 at 14:04
90

Here my solution for everyone out there looking for a non-jQuery code (pure javascript)

document.getElementById("clickable").addEventListener("click", function(e) {
    e = window.event || e; 
    if(this === e.target) {
      // put your code here
    }
});

Your code wont be executed if clicked on parent's children

4
  • 1
    This worked for me, I needed a non-JS/jQuery solution. 10x!
    – L A
    Commented Sep 27, 2016 at 14:08
  • 5
    Great answer. I just passed the event directly. So I did not use window.event, which MDN discourages: developer.mozilla.org/en-US/docs/Web/API/Window/event. If you can spare the time I would appreciate it if you can comment why you did use window.event ( maybe it is an issue that existed in 2015 or I failed to understand the reason ). Commented May 3, 2019 at 12:30
  • it doesnt work, tested it
    – showtime
    Commented Mar 25, 2022 at 11:25
  • 1
    if ( this !== e.target ) return; works better than the positive form, since it avoids nesting and makes it clearer that we're stopping when the current case doesn't pertain us.
    – zakmck
    Commented Jul 18, 2023 at 8:32
37

If you do not intend to interact with the inner element/s in any case, then a CSS solution might be useful for you.

Just set the inner element/s to pointer-events: none

in your case:

.clickable > a {
    pointer-events: none;
}

or to target all inner elements generally:

.clickable * {
    pointer-events: none;
}

This easy hack saved me a lot of time while developing with ReactJS

Browser support could be found here: http://caniuse.com/#feat=pointer-events

2
  • what if you want to have other event listeners in child elements? Your approach would prevent you from doing that.
    – showtime
    Commented Mar 25, 2022 at 11:31
  • As mentioned in the answer, this is "If you do not intend to interact with the inner element/s in any case". Otherwise you have to seek other solutions. Commented Apr 14, 2022 at 13:51
31

Inline Alternative:

<div>
  <!-- Other content. -->
  <a onclick='event.stopPropagation();' href="http://foo.example">I don't want #clickable to handle this click event.</a>
</div>
18

You can also try this

$("#clickable").click(function(event) {
    var senderElementName = event.target.tagName.toLowerCase();
    if(senderElementName === 'div') {
        // Do something here 
    } else {
        // Do something with <a> tag
    }
});
0
12

Writing if anyone needs (worked for me):

event.stopImmediatePropagation()

From this solution.

10

I compare to ev.currentTarget when this is not available (React, etc).

$("#clickable").click(function(e) {
    if (e.target === e.currentTarget) {
        window.location = url;
        return true;
    }
})
9

Using return false; or e.stopPropogation(); will not allow further code to execute. It will stop flow at this point itself.

1
  • Yes, this is important - ran into this myself. But the answer above from Rex is helpful - can get the element that was clicked, and in some cases use this in the logic that you are trying to stop. .target.nodeName was also helpful to get a clear idea of what was hit. Commented May 9, 2016 at 20:33
8

If you have multiple elements in the clickable div, you should do this:

$('#clickable *').click(function(e){ e.stopPropagation(); });
4

e.stopPropagation() is a correct solution, but in case you don't want to attach any event handler to your inner anchor, you can simply attach this handler to your outer div:

e => { e.target === e.currentTarget && window.location = URL; }
3

Here's an example using Angular 2+

For example, if you wanted to close a Modal Component if the user clicks outside of it:

// Close the modal if the document is clicked.

@HostListener('document:click', ['$event'])
public onDocumentClick(event: MouseEvent): void {
  this.closeModal();
}

// Don't close the modal if the modal itself is clicked.

@HostListener('click', ['$event'])
public onClick(event: MouseEvent): void {
  event.stopPropagation();
}
3

var inner = document.querySelector("#inner");
var outer = document.querySelector("#outer");
inner.addEventListener('click',innerFunction);
outer.addEventListener('click',outerFunction);

function innerFunction(event){
  event.stopPropagation();
  console.log("Inner Functiuon");
}

function outerFunction(event){
  console.log("Outer Functiuon");
}
<!DOCTYPE html>
<html>
<head>
  <meta charset="utf-8">
  <meta name="viewport" content="width=device-width">
  <title>Pramod Kharade-Event with Outer and Inner Progration</title>
</head>
<body>
<div id="outer" style="width:100px;height:100px;background-color:green;">
  <div id="inner" style="width:35px;height:35px;background-color:yellow;"></div>
</div>
</body>
</html>

3

If it is in inline context, in HTML try this:

onclick="functionCall();event.stopPropagation();
1

You need to stop the event from reaching (bubbling to) the parent (the div). See the part about bubbling here, and jQuery-specific API info here.

1
  • Cool. Thanks for the info about event bubbling. Commented Sep 2, 2009 at 17:40
1

for those that are not using jQuery

document.querySelector('.clickable').addEventListener('click', (e) =>{
    if(!e.target.classList.contains('clickable')) return
    // place code here
})
1
  • Hello & thank you! this appears to largely duplicate an existing answer ( stackoverflow.com/a/29499060 ) Please edit to explain how this is different / better than existing answers!
    – Edward
    Commented Jan 20, 2023 at 20:42
1

Here is a react based solution example. In my case I had a modal contact form that had a transparent outer wrapper. I wanted any click outside of the modal to close the modal.

import React, { useState } from 'react';

function Component() {
  const [contactOpen, setContactOpen] = useState(false);
  const handleContactToggle = () => {
    if (e.target === e.currentTarget) {
      //e.target ===  item the onClick is attached to. 
      //e.currentTarget ===  item that received the click
      // If these do not match the click is somewhere inside the InnerComponent
      setContactOpen(!contactOpen);
    }
  };
  const ContactModalClass = (contactOpen) ? styles.contactModalOpen : styles.contactModalClosed

  function handleModalToggle(e) {
    if (e.target === e.currentTarget) {
      handleContactToggle();
    }
  }
  <div className={ContactModalClass} onClick={e => handleContactToggle(e)} id='OuterWrapper-Click-To-Close'>
    <InnerComponent id='Inner-Form-Click-Does-Not-Trigger-Outer-Function' />
  </div>
}

Note: Question appeared for my react search hence the react answer.

0

To specify some sub element as unclickable write the css hierarchy as in the example below.

In this example I stop propagation to any elements (*) inside td inside tr inside a table with the class ".subtable"

$(document).ready(function()
{    
   $(".subtable tr td *").click(function (event)
   {
       event.stopPropagation();
   });

});
0

You can check whether the target is not your div-element and then issue another click event on the parent after which you will "return" from the handle.

$('clickable').click(function (event) {
    let div = $(event.target);
    if (! div.is('div')) {
       div.parent().click();
       return;
    }
    // Then Implement your logic here
}
0

Here is a non jQuery solution that worked for me.

<div style="background:cyan; width:100px; height:100px;" onclick="if (event.srcElement==this) {console.log('outer');}">
    <a style="background:red" onclick="console.log('inner');">Click me</a>
</div>

0

In case anybody is finding this post and using an anchor tag as their parent element, you should try:

event.preventDefault()

in your child onclick event. Found this solution here: https://stackoverflow.com/a/1607890/17225652

-1

In case someone had this issue using React, this is how I solved it.

scss:

#loginBackdrop {
position: absolute;
width: 100% !important;
height: 100% !important;
top:0px;
left:0px;
z-index: 9; }

#loginFrame {
width: $iFrameWidth;
height: $iFrameHeight;
background-color: $mainColor;
position: fixed;
z-index: 10;
top: 50%;
left: 50%;
margin-top: calc(-1 * #{$iFrameHeight} / 2);
margin-left: calc(-1 * #{$iFrameWidth} / 2);
border: solid 1px grey;
border-radius: 20px;
box-shadow: 0px 0px 90px #545454; }

Component's render():

render() {
    ...
    return (
        <div id='loginBackdrop' onClick={this.props.closeLogin}>
            <div id='loginFrame' onClick={(e)=>{e.preventDefault();e.stopPropagation()}}>
             ... [modal content] ...
            </div>
        </div>
    )
}

By a adding an onClick function for the child modal (content div) mouse click events are prevented to reach the 'closeLogin' function of the parent element.

This did the trick for me and I was able to create a modal effect with 2 simple divs.

-1

If a child element is clicked, then the event bubbles up to the parent and event.target !== event.currentTarget.

So in your function, you can check this and return early, i.e.:

var url = $("#clickable a").attr("href");
$("#clickable").click(function(event) {
    if ( event.target !== event.currentTarget ){
        // user clicked on a child and we ignore that
        return;
    }
    window.location = url;
    return true;
})
-2

This is what you are looking for

mousedown event. this works on every DOM elements to prevent javascript focus handler like this:

$('.no-focus').mousedown(function (e) {
   e.prevenDefault()

   // do stuff
}

in vue.js framework, you can use modifier like this:

<span @mousedown.prevent> no focus </span>

Note that using on the input will prevent text selection handler

-3

add a as follows:

<a href="http://foo.example" onclick="return false;">....</a>

or return false; from click handler for #clickable like:

  $("#clickable").click(function() {
        var url = $("#clickable a").attr("href");
        window.location = url;
        return false;
   });
-4

All solution are complicated and of jscript. Here is the simplest version:

var IsChildWindow=false;

function ParentClick()
{
    if(IsChildWindow==true)
    {
        IsChildWindow==false;
        return;
    }
    //do ur work here   
}


function ChildClick()
{
    IsChildWindow=true;
    //Do ur work here    
}
1
  • 3
    i think you made a mistake in line "IsChildWindow==false;" - shouldn't it be "IsChildWindow = false;"? Commented Jan 26, 2012 at 12:31
-5
<a onclick="return false;" href="http://foo.example">I want to ignore my parent's onclick event.</a>
3
  • 6
    This also prevents the link from navigating.
    – Rex M
    Commented Sep 2, 2009 at 17:28
  • Yes, or do not what is needed?. Or need to be nevegar? Commented Sep 2, 2009 at 18:12
  • 1
    Please read How do I write a good answer?. While this code block may answer the OP's question, this answer would be much more useful if you explain how this code is different from the code in the question, what you've changed, why you've changed it and why that solves the problem without introducing others. Commented Jun 25, 2022 at 13:41

Not the answer you're looking for? Browse other questions tagged or ask your own question.