I have a simple overlay that I want to catch click events on. Problem is, I don't want any clicks that occur within the content of the overlay to trigger an event. For example, if you look at my code snippet below, clicking inside the .content div should not trigger the click event listener that I set on the overlay, but it does.
Basically I want to just know when someone clicks the black background of the overlay. Is there anyway to do this with how I currently have my code?
const overlay = document.querySelector('.overlay')
overlay.onclick = function() {
console.log('click on overlay!')
}
body {
margin: 0;
}
.overlay {
position: fixed;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
width: 100%;
height: 100%;
z-index: 10;
}
.content {
width: 200px;
height: 200px;
position: absolute;
z-index: 11;
top: calc(50% - 100px);
left: calc(50% - 100px);
background: white;
display: flex;
align-items: center;
justify-content: center;
}
<div class="overlay">
<div class="content">Hello World</div>
</div>
you can disable the click event for the content div
const content = document.querySelector('.content');
content.off('click');
To solve this problem of yours you need to understand how javascript events works. There are three phases of event:
Capturing phase:
When you trigger some event javascript starts to handle it by passing from the very top element(Window) to children. It happens until target(.content) element reached. In your case event goes through .overlay element but event handler not triggered, because by default all event listeners triggers on bubbling or target phase
Target phase:
The event has arrived at the event's target. The very element on which element was triggered, which in your case is .content
Bubbling phase:
The event is propagating back up through the target's ancestors in reverse order, starting with the parent and eventually reaching the containing Window. During this phase your event passing through .overlay element and invokes event handler which was registered.
I don't know what is best solution for your problem but it can be solved in several ways:
Solution proposed by @PsiKai and @Joulss where you're checking target element by class name. Registered event listener
Solution proposed by @eMentorship. By changing the markup, event at bubbling phase doesn't touch .overlay element.
const content = document.querySelector('.element');
content.addEventListener('click', event => event.stopPropagation());
By calling stopPropagation you stoping event from going to the parent element and as a result .overlay event handler ignored as event not bubbling to the root element.
Event phase: https://developer.mozilla.org/en-US/docs/Web/API/Event/eventPhase
PS. According to MDN: The addEventListener() method is the recommended way to register an event listener. The benefits are as follows:
Just restructure your HTML code and it will work fine, as you have already set the z-index for overlay and content as well. so as content has a higher z-index than the overlay, so it will be hidden by the content.
Demo:
const overlay = document.querySelector('.overlay')
overlay.onclick = function() {
console.log('click on overlay!')
}
body {
margin: 0;
}
.popup {
position: fixed;
top: 0;
left: 0;
width: 100%;
height: 100%;
z-index: 10;;
}
.overlay {
position: fixed;
top: 0;
left: 0;
background-color: rgba(0,0,0,0.5);
width: 100%;
height: 100%;
z-index: 10;
}
.content {
width: 200px;
height: 200px;
position: absolute;
z-index: 11;
top: calc(50% - 100px);
left: calc(50% - 100px);
background: white;
display: flex;
align-items: center;
justify-content: center;
}
<div class="popup">
<div class="overlay"></div>
<div class="content">Hello World</div>
</div>