</>
Skip to content
JavaScript lessons (17/64)

JavaScript — Events

The event-driven model

Nothing happens until something happens:

wait → event occurs → browser creates event → listeners run → app updates

Events come from everywhere:

click · submit · input · keydown · load · scroll · resize · online

Listeners

element.addEventListener("click", handler);

function handler(event) {
    console.log(event.type);         // "click"
    console.log(event.target);       // origin element
    console.log(event.currentTarget);// element running this listener
}

Removal requires the same reference:

element.removeEventListener("click", handler);

Default actions

Many events have built-in behavior — links navigate, forms submit, keys type text. Cancel deliberately:

link.addEventListener("click", e => e.preventDefault());
form.addEventListener("submit", e => { e.preventDefault(); /* own logic */ });

Propagation

capture phase ↓ target ↓ bubble phase ↑

An event on a button first descends to it (capture), then bubbles back up through ancestors. Listeners default to bubbling.

<div id="parent"><button id="child">Click</button></div>

Both listeners fire on one click — child's first, then parent's. event.stopPropagation() halts the climb (use sparingly).

Event delegation — the payoff

One listener manages unlimited children via bubbling + closest:

container.addEventListener("click", event => {
    const button = event.target.closest("button");
    if (!button) return;
    handle(button.dataset.action);
});

Immune to dynamically added elements — the standard for lists, tables, toolbars.

Custom events — components talking

const loginEvent = new CustomEvent("user:login", {
    detail: { id: 42 }                 // your payload
});

document.dispatchEvent(loginEvent);

document.addEventListener("user:login", e => {
    console.log(e.detail.id);          // 42
});

Namespaced names (user:login) avoid collisions. Decouples modules: dispatchers needn't know listeners exist.

Listener options recap

el.addEventListener(type, handler, {
    once: true,           // auto-remove after first fire
    capture: true,        // run during capture phase
    passive: true,        // promise: no preventDefault (scroll perf)
    signal: controller.signal   // bulk removal via AbortController
});
const controller = new AbortController();
// …attach many with { signal: controller.signal }
controller.abort();       // all removed together

Common gotcha

button.addEventListener("click", handler());   // ❌ invokes immediately
button.addEventListener("click", handler);     // ✓ passes the function

Mini Practice

  1. Attach named + anonymous handlers; remove the named one only.
  2. preventDefault on a link; log instead.
  3. Map out bubbling for three nested divs.
  4. Delegated delete buttons inside a re-rendered list.
  5. Custom "cart:updated" event carrying item count in detail.
  6. Bulk-cleanup with AbortController.

Next: math →

Related Topics

Frequently Asked Questions about Events

What is Events in JavaScript?

Events is a fundamental concept in JavaScript. This lesson explains it step by step with clear examples, making it easy for beginners to understand.

How do I learn Events?

Start by reading the explanation above, then try the code examples. Practice by modifying the examples and experimenting with different values. Hands-on practice is the best way to learn Events.

Why is Events important in JavaScript?

Events is essential for JavaScript development. Understanding this concept will help you write better code and solve real-world problems more effectively.