What you'll learn
Events turn browser input into application intent. Robust handlers understand propagation, delegate repeated controls, and preserve native keyboard behavior.
By the end of this lesson, you'll be able to:
- Register and remove listeners
- Explain capture and bubbling
- Use delegation for dynamic interfaces
Core mental model
Use this decision table as a compact reference. Focus on what each tool means and when it earns its place in production code.
| Concept | What it means | Decision rule |
|---|---|---|
| Event target | The deepest node that initiated the event | Use closest() to resolve an intended control |
| Current target | The node whose listener is running | Use for the delegated container |
| Delegation | One ancestor handles matching descendants | Use for repeated or dynamically added controls |
Professional workflow
Build the behavior in small, observable steps. Each step should leave something you can inspect or test.
- Describe the event interaction boundary: inputs, outputs, state, timing, and expected failures.
- Implement the smallest correct path with names that expose intent.
- Add edge cases and failure handling before introducing abstractions.
- Verify behavior with realistic data and one deliberately adversarial example.
- Refactor only after the observable behavior is protected.
Make behavior observable
Guided code lab
Delegate a module list
One listener handles every current and future button.
const list = document.querySelector("#modules");
list.addEventListener("click", event => {
const button = event.target.closest("button[data-module]");
if (!button || !list.contains(button)) return;
console.log("Open module", button.dataset.module);
});Clean up with AbortController
One abort signal can remove a feature's listeners together.
const controller = new AbortController();
window.addEventListener("resize", () => console.log("resized"), {
signal: controller.signal,
});
document.querySelector("#close").addEventListener("click", () => {
controller.abort();
}, { once: true });Production practice
Contract
Keep the event interaction API explicit: accepted state, emitted events, DOM ownership, and cleanup.
Verification
Test with keyboard input, missing elements, repeated initialization, and teardown—not only a mouse happy path.
Operations
Measure user-visible latency and remove listeners, observers, object URLs, or media tracks when the feature ends.
Common failure mode
Independent workshop
Create an accessible accordion with delegated controls and removable listeners.
Your finished workshop must include:
- Native buttons
- aria-expanded synchronized with state
- One delegated listener and a cleanup path
Definition of done
Recap & quick check
Key takeaways
- Events travel through capture and bubble phases
- target and currentTarget differ
- Delegation scales repeated controls
- Listeners need lifecycle cleanup
Quick check
1. Which property is the original deepest node?
2. What does once: true do?
3. Why use closest() in delegation?
Keep the workshop. Later modules deliberately build on these decisions, so each exercise can become part of your final portfolio architecture.