JavaScript
Completed
-
Section 1: Getting Started
-
Section 2: Core Syntax and Types
-
Section 3: Strings and Numbers in Depth
-
Section 4: Control Flow
-
Section 5: Functions
-
Section 6: Objects and Arrays
-
Section 7: Maps, Sets, and Symbols
-
Section 8: Asynchronous JavaScript
-
Section 9: Object-Oriented and Prototypes
-
Section 10: The DOM
-
Section 11: Browser APIs
-
Section 12: Modern JavaScript (ES2015-ES2025)
-
Section 13: Functional Programming Patterns
-
Section 14: Error Handling and Debugging
-
Section 15: Testing
-
Section 16: Accessibility for JavaScript Developers
-
Section 17: Internationalization and Localization
-
Section 18: Performance
-
Section 19: Node.js Fundamentals
-
Section 20: Regular Expressions
-
Section 21: Design Patterns in JavaScript
-
Section 22: Security Basics
-
Section 23: Data Structures and Algorithms in JavaScript
-
Section 24: Practical Projects
-
Section 25: More Advanced Async Patterns
-
Section 26: More Object and Class Practice
-
Section 27: Working with Dates and Internationalization
-
Section 28: Web Components
-
Section 29: More DOM and Browser Practice
-
Section 30: Build Tooling for Vanilla JavaScript
-
Section 31: More Practice Projects
-
Section 32: Interview and Algorithm Practice
-
Section 33: Error Objects (MDN Reference)
-
Section 34: TypedArrays and Binary Data
-
Section 35: Reflection and Metaprogramming (MDN Reference)
-
Section 36: More Global Functions (MDN Reference)
83: Event Bubbling and Capturing
Imagine you work in a corporate office. You're a junior developer, and your boss is the manager, and their boss is the director. If a client sends you a direct email with a complaint, you're the first person to see it. But in a corporate environment, that email doesn't just stay with you. You might handle it, but the manager is CC'd, and the director is also looped in. The "event" (the complaint) starts at the bottom and ripples upward through the chain of command.
In JavaScript, this is exactly how events work. When you click a button, you aren't just clicking that button; you're also clicking the div that contains the button, the section that contains the div, and eventually the body and the window. The browser handles this in two directions: Bubbling and Capturing.
The Default Ride Upwards
By default, almost every event you'll use in JavaScript "bubbles." This means the event starts at the most specific element (the target) and moves up the DOM tree to the root. I've seen countless developers get frustrated when they put a click listener on a card and a click listener on a button inside that card, only to find that clicking the button triggers both functions.
<div id="product-card" style="padding: 20px; background: lightgrey;">
Product Name
<button id="buy-btn">Buy Now</button>
</div>
<script>
const card = document.querySelector('#product-card');
const btn = document.querySelector('#buy-btn');
card.addEventListener('click', () => {
console.log('Card clicked!');
});
btn.addEventListener('click', () => {
console.log('Button clicked!');
});
</script>
If you run this and click the "Buy Now" button, your console will show "Button clicked!" followed immediately by "Card clicked!". The event bubbled up from the button to the card. This is actually incredibly useful for something called "Event Delegation," where you listen for events on a parent rather than attaching a hundred listeners to a hundred different children.
Intercepting the Event on the Way Down
Now, capturing is the opposite. It's like the director seeing the email before it ever reaches your inbox. The event starts at the window and trickles down to the target. You rarely use this in day-to-day coding, but it's a lifesaver when you need to intercept an event before it reaches a child element.
To enable capturing, you pass a third argument—a boolean true—to addEventListener. If you don't provide this, it defaults to false (bubbling).
// This listener will fire BEFORE the button's own listener
card.addEventListener('click', () => {
console.log('Card intercepted the click first!');
}, true);
Cutting the Signal
Sometimes, you just want the event to stop. If you're building a dropdown menu, you might have a "Delete" button inside a clickable row. You don't want the "Row Selected" event to fire just because the user wanted to delete the item. This is where event.stopPropagation() comes in.
I like to think of this as the "emergency brake." It tells the browser, "I've handled this; don't let anyone else in the chain know about it."
btn.addEventListener('click', (event) => {
event.stopPropagation();
console.log('Only the button will fire. The card will never know.');
});
A quick word of caution: use stopPropagation() sparingly. If you kill the event bubble, other global scripts or analytics tools that are listening for clicks at the document level might stop working, and you'll be left scratching your head wondering why your tracking pixels aren't firing.
📋 Practical Task
Build a Nested Category Filter
Your goal is to create a simple category navigation system where clicking a specific sub-category doesn't trigger the main category's "General Search" function.
Requirements:
- Create a
divwith the IDcategory-containerand abuttoninside it with the IDsub-category-btn. - Add a click event listener to
category-containerthat logs:"Performing general category search..." - Add a click event listener to
sub-category-btnthat logs:"Filtering by specific sub-category!" - Implement the logic so that when the
sub-category-btnis clicked, only its own message appears in the console, preventing thecategory-containerlistener from firing.
There are no comments for now.