JavaScript Events (Part 2) Propagation: Bubbling, Capturing, Deligation, Target and many more in depth
What is event propagation?
Event propagation refers to the process by which events are handled in a software application, particularly in the context of graphical user interfaces (GUIs) or web development. Events can be user actions, such as clicking a button or pressing a key, or system-generated events, like a timer expiring. Understanding event propagation is crucial for developing interactive and responsive applications.
There are two main phases in event propagation: the capturing phase and the bubbling phase. These phases describe the order in which the event is processed as it travels through the hierarchy of elements in the DOM (Document Object Model) in the case of web development.
In thiseventListeners
, we saw two arguments: one is the event, and the other is the callback function. But there is also a third argument, which is a boolean (true or false) value that causes the propagation of an event (event bubbling or event capturing). By default, the third argument is false.
What is event capturing?
Event capture is one phase of event propagation in the DOM that occurs when an event is triggered on an HTML element. Event capture happens during the first phase of this flow. Before the event reaches the target element, it goes through the capture phase. The event starts from the root of the DOM tree and moves towards the target element.
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
}
body,#grandParent,#parent,#child{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 25px;
}
#grandParent{
width: 900px;
height: 650px;
background-color: rgb(17, 17, 17);
color: white;
margin-top: 50px;
}
#parent{
width: 700px;
height: 450px;
background-color: yellowgreen;
color: white;
margin-top: 20px;
color: black;
}
#child{
width: 500px;
height: 200px;
background-color: black;
color: white;
padding: 20px;
}
</style>
</head>
<body>
<div id="grandParent">
<h1>
Grand Parent Div
</h1>
<div id="parent">
<h1>
Parent Div
</h1>
<div id="child">
<h1>
Child Div
</h1>
</div>
</div>
</div>
</body>
</html>
Then, in a JavaScript file, you have to write this code to understand the capture of the event
let grandParent = document.getElementById('grandParent');
let parent = document.getElementById('parent');
let child = document.getElementById('child');
grandParent.addEventListener('click', ()=>{
alert('Grand Parent div is called');
}, true);
parent.addEventListener('click', ()=>{
alert('Parent div is called');
}, true);
child.addEventListener('click', ()=>{
alert('Child div is called');
}, true);
In the above JS code, we will see the third boolean argument. If that argument is true, then the event starts from the root of the DOM tree and moves towards the target element, meaning if you click on the child element, then the Grand Parent Div
calls first, then the Parent Div
calls, and then the Child Div
calls. It comes from the top to the bottom of the web page.
What is event bubbling?
Event bubbling is a phase in the event propagation model of the DOM that occurs when an event is triggered on an HTML element. Event bubbling happens during the second phase of this flow. After the event reaches the target, it enters the bubbling phase. The event then starts to bubble up from the target element towards the root of the DOM tree. During this phase, the event is propagated through the ancestors of the target element.
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
}
body,#grandParent,#parent,#child{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 25px;
}
#grandParent{
width: 900px;
height: 650px;
background-color: rgb(17, 17, 17);
color: white;
margin-top: 50px;
}
#parent{
width: 700px;
height: 450px;
background-color: yellowgreen;
color: white;
margin-top: 20px;
color: black;
}
#child{
width: 500px;
height: 200px;
background-color: black;
color: white;
padding: 20px;
}
</style>
</head>
<body>
<div id="grandParent">
<h1>
Grand Parent Div
</h1>
<div id="parent">
<h1>
Parent Div
</h1>
<div id="child">
<h1>
Child Div
</h1>
</div>
</div>
</div>
</body>
</html>
Then, in a JavaScript file, you have to write this code to understand the bubbling of the event
let grandParent = document.getElementById('grandParent');
let parent = document.getElementById('parent');
let child = document.getElementById('child');
grandParent.addEventListener('click', ()=>{
alert('Grand Parent div is called');
}, false);
parent.addEventListener('click', ()=>{
alert('Parent div is called');
}, false);
child.addEventListener('click', ()=>{
alert('Child div is called');
}, false);
In the above JS code, we will see the third boolean argument. If that argument is false, then the event starts from the target element and moves towards the root of the DOM tree, meaning if you click on the child element, then the Child Div
calls first, then the Parent Div
calls, and then the Grand Parent Div
calls. It comes from the bottom to the top of the web page. By default, it is false. If you don't write the argument as false, then it is considered false.
You can also understand the event propagation concept with the help of the image given below.
What is event delegation?
Event delegation is a programming concept often used in web development, particularly in DOM manipulation. It involves handling events on a parent element rather than on the individual child elements that might trigger the event. It means you don't need to put event listeners individually on every single element; you just put event listeners on the parent or grandparent element. This technique offers several advantages, including improved performance and simplification of code, especially in situations where there are many dynamically created elements.
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
}
body,#grandParent,#parent,#child{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 25px;
}
#grandParent{
width: 900px;
height: 650px;
background-color: rgb(17, 17, 17);
color: white;
margin-top: 50px;
}
#parent{
width: 700px;
height: 450px;
background-color: yellowgreen;
color: white;
margin-top: 20px;
color: black;
}
#child{
width: 500px;
height: 200px;
background-color: black;
color: white;
padding: 20px;
}
</style>
</head>
<body>
<div id="grandParent">
<h1>
Grand Parent Div
</h1>
<div id="parent">
<h1>
Parent Div
</h1>
<div id="child">
<h1>
Child Div
</h1>
</div>
</div>
</div>
</body>
</html>
Then, in a JavaScript file, you have to write this code to understand the bubbling of the event
let grandParent = document.getElementById('grandParent');
grandParent.addEventListener('click', ()=>{
alert('Grand Parent div is called');
}, false);
In the above code, we add a click event for just the grandparent div. When you click on a child element, the browser tries to find the event on the child; if it finds nothing there, then the browser bubbles up and goes toward its parent element, and if there is nothing, then it bubbles up to its grandparent element and finds the event. Once it finds it, it calls its callback function. This is the event delegation.
target
Thetarget
property represents the element on which the event was originally triggered or the element that triggered the event. This property returns the reference to the DOM element that was the source of the event.
In the event delegation, we saw that we added a click event for just the grandparent div. What if you want to access the child, parent, and grandparent divisions individually? This could be done by event objects that have a target and current target properties.
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
}
body,#grandParent,#parent,#child{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 25px;
}
#grandParent{
width: 900px;
height: 650px;
background-color: rgb(17, 17, 17);
color: white;
margin-top: 50px;
}
#parent{
width: 700px;
height: 450px;
background-color: yellowgreen;
color: white;
margin-top: 20px;
color: black;
}
#child{
width: 500px;
height: 200px;
background-color: black;
color: white;
padding: 20px;
}
</style>
</head>
<body>
<div id="grandParent">
<h1>
Grand Parent Div
</h1>
<div id="parent">
<h1>
Parent Div
</h1>
<div id="child">
<h1>
Child Div
</h1>
</div>
</div>
</div>
</body>
</html>
For example, in a JavaScript file, you have to write this code to understand the object of the event( we write it as e).
let grandParent = document.getElementById('grandParent');
grandParent.addEventListener('click', (e)=>{
console.log(e.target);
}, false);
After applying this code, when you click on a child, in the console, you can see that you clicked on the child element only. and the same for the parent and grandparent div.
currentTarget
ThecurrentTarget
property represents the element to which the event handler is currently attached. This property remains constant throughout the event propagation, regardless of where the event originated. It is particularly useful when dealing with event delegation, where a common ancestor is used to listen for events on multiple child elements.
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
}
body,#grandParent,#parent,#child{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 25px;
}
#grandParent{
width: 900px;
height: 650px;
background-color: rgb(17, 17, 17);
color: white;
margin-top: 50px;
}
#parent{
width: 700px;
height: 450px;
background-color: yellowgreen;
color: white;
margin-top: 20px;
color: black;
}
#child{
width: 500px;
height: 200px;
background-color: black;
color: white;
padding: 20px;
}
</style>
</head>
<body>
<div id="grandParent">
<h1>
Grand Parent Div
</h1>
<div id="parent">
<h1>
Parent Div
</h1>
<div id="child">
<h1>
Child Div
</h1>
</div>
</div>
</div>
</body>
</html>
For example, in a JavaScript file, you have to write this code to understand the object of the event( we write it as e).
let grandParent = document.getElementById('grandParent');
grandParent.addEventListener('click', (e)=>{
console.log(e.currentTarget);
}, false);
After applying this code, when you click on a child, parent, or grandparent in the console, you can see that you clicked on the grandparent element only because the event is added to that div.
Let's talk about some other properties of the event
srcElement
srcElement
is a property that was historically used in the DOM to refer to the element that triggered an event. However, it's important to note that thissrcElement
is a non-standard property and was primarily used in Internet Explorer.
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
}
body,#grandParent,#parent,#child{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 25px;
}
#grandParent{
width: 900px;
height: 650px;
background-color: rgb(17, 17, 17);
color: white;
margin-top: 50px;
}
#parent{
width: 700px;
height: 450px;
background-color: yellowgreen;
color: white;
margin-top: 20px;
color: black;
}
#child{
width: 500px;
height: 200px;
background-color: black;
color: white;
padding: 20px;
}
</style>
</head>
<body>
<div id="grandParent">
<h1>
Grand Parent Div
</h1>
<div id="parent">
<h1>
Parent Div
</h1>
<div id="child">
<h1>
Child Div
</h1>
</div>
</div>
</div>
</body>
</html>
For example, in a JavaScript file, you have to write this code to understand the srcElement of the event property( we write it as e).
let grandParent = document.getElementById('grandParent');
grandParent.addEventListener('click', (e)=>{
console.log(e.srcElement);
}, false);
Note:
In modern web development, it's recommended to use the standard property target
instead, which is supported across various browsers. Thetarget
property also refers to the element that triggered the event.
If you are dealing with older code or a specific environment where srcElement
is still used, you should be aware that it may not work in all browsers, and it's generally better to update the code to use the more widely supported target
property.
stopPropagation()
In the context of the DOM in web development, the stopPropagation
method is used to prevent the further propagation of an event through the DOM hierarchy. When an event occurs on a particular element, it can trigger handlers not only on that element but also on its ancestors or descendants, depending on the event phase (capturing or bubbling).
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
}
body,#grandParent,#parent,#child{
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
border-radius: 25px;
}
#grandParent{
width: 900px;
height: 650px;
background-color: rgb(17, 17, 17);
color: white;
margin-top: 50px;
}
#parent{
width: 700px;
height: 450px;
background-color: yellowgreen;
color: white;
margin-top: 20px;
color: black;
}
#child{
width: 500px;
height: 200px;
background-color: black;
color: white;
padding: 20px;
}
</style>
</head>
<body>
<div id="grandParent">
<h1>
Grand Parent Div
</h1>
<div id="parent">
<h1>
Parent Div
</h1>
<div id="child">
<h1>
Child Div
</h1>
</div>
</div>
</div>
</body>
</html>
In a JavaScript file, if you have this code then
let grandParent = document.getElementById('grandParent');
let child = document.getElementById('child');
grandParent.addEventListener('click', (e)=>{
console.log('Divisions are clicked');
});
child.addEventListener('click', (e)=>{
console.log('Child div is clicked');
});
After applying this JavaScript code, when you click on the grandparent or parent div then in the console message appears that (Divisions are clicked
) but when you click on the child element then two messages appear: first is (Child div is clicked
) and then the event is bubbled up and a second message appears instantly (Divisions are clicked
). Sometimes you don't need this propagation or bubbling in the event so you can stop it by using stopPropagation()
on the targetted event.
So, you have to write this code to understand the concept stopPropagation()
of the event( we write it as e). After writing this code if you click on the child element then in the console it only shows that (Child div is clicked
) and the event is not bubbled up.
let grandParent = document.getElementById('grandParent');
let child = document.getElementById('child');
grandParent.addEventListener('click', (e)=>{
console.log('Divisions are clicked');
});
child.addEventListener('click', (e)=>{
console.log('Child div is clicked');
e.stopPropagation(); // This will stop bubbling on this event
});
preventDefault()
In the DOM, preventDefault()
is a method that is commonly used in the context of handling events. It is part of the Event interface and is used to stop the default action associated with an event from occurring. When an event occurs on an HTML element (e.g., a button click, or a form submission), the browser performs a default action associated with that event. For example, clicking on a link navigates to the URL specified in the link's href
attribute, or submitting a form sends data to the server.
For example, if you have HTML documents given below
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Understanding DOM Events</title>
<style>
body{
margin: 0;
padding: 0;
box-sizing: border-box;
background-color: #212121;
height: 700px;
}
body,#grandParent{
display: grid;
place-items: center;
border-radius: 25px;
}
#grandParent{
width: 500px;
height: 350px;
background-color: rgb(17, 17, 17);
color: white;
}
</style>
</head>
<body>
<div id="grandParent">
<ul>
<li>Home</li>
<li>About</li>
<li><a href="https://www.google.com/" id="href">Google</a></li>
</ul>
</div>
</body>
</html>
In a JavaScript file, if you have this code then if you click on Google
no action is being performed.
let href = document.getElementById('href');
href.addEventListener('click', (e)=>{
console.log('href is clicked');
e.preventDefault();
});
We will practice DOM by projects in the next blogs.
Subscribe to my newsletter
Read articles from Muhammad Bilal directly inside your inbox. Subscribe to the newsletter, and don't miss out.
Written by
Muhammad Bilal
Muhammad Bilal
With a passion for creating seamless and visually appealing web experiences, I am Muhammad Bilal, a dedicated front-end developer committed to transforming innovative ideas into user-friendly digital solutions. With a solid foundation in HTML, CSS, and JavaScript, I specialize in crafting responsive and intuitive websites that captivate users and elevate brands. 📈 Professional Experience: In my two years of experience in front-end development, I have had the privilege of collaborating with diverse teams and clients, translating their visions into engaging online platforms. 🔊 Skills: Technologies: HTML5, CSS3, JavaScript, WordPress Responsive Design: Bootstrap, Tailwind CSS, Flexbox, and CSS Grid Version Control: Git, GitHub 🖥 Projects: I have successfully contributed to projects where my focus on performance optimization and attention to detail played a crucial role in delivering high-quality user interfaces. ✨ Continuous Learning: In the fast-paced world of technology, I am committed to staying ahead of the curve. Regularly exploring new tools and methodologies, I am dedicated to enhancing my skills and embracing emerging trends to provide the best possible user experience. 🎓 Education: I hold a BSc degree in Software Engineering from Virtual University, where I gained both technical skills and knowledge. 👥 Let's Connect: I am always open to new opportunities, collaborations, and discussions about the exciting possibilities in front-end development. Feel free to reach out via LinkedIn, Instagram, Facebook, Twitter, or professional email.