Skip to main content

JavaScript Events

JavaScript Custom Events

Written by Published

A custom event lets one part of your code announce something to another.

You are not limited to the events the browser provides.

CustomEvent creates your own, with any data attached.

Example

Example

javascript

document.body.innerHTML = '<div id="cart"></div>';

const cart = document.getElementById("cart");

cart.addEventListener("itemAdded", function (event) {
  console.log("added " + event.detail.name);
});

cart.dispatchEvent(new CustomEvent("itemAdded", {
  detail: { name: "Book" }
}));

The output is added Book.

Creating and Firing

new CustomEvent(name, options) creates the event.

detail carries any data you want to send with it.

dispatchEvent fires it on an element.

Syntax

Syntax

javascript

element.dispatchEvent(new CustomEvent("name", {
  detail: { key: "value" }
}));

Listening for one works exactly like a built-in event.

Passing Data

Everything you send arrives in event.detail.

Example

Example

javascript

document.body.innerHTML = '<div id="box"></div>';

const box = document.getElementById("box");

box.addEventListener("saved", function (event) {
  console.log(event.detail.id + " at " + event.detail.time);
});

box.dispatchEvent(new CustomEvent("saved", {
  detail: { id: 7, time: "now" }
}));

The output is 7 at now.

Custom Events Do Not Bubble by Default

Built-in events usually bubble, but yours do not unless you say so.

This catches people out when the listener is on a parent.

Example

Example

javascript

document.body.innerHTML = '<div id="outer"><div id="inner"></div></div>';

let heard = 0;

document.getElementById("outer").addEventListener("ping", function () {
  heard = heard + 1;
});

document.getElementById("inner").dispatchEvent(new CustomEvent("ping"));
document.getElementById("inner").dispatchEvent(
  new CustomEvent("ping", { bubbles: true })
);

console.log(heard);

Only the bubbling one reached the parent, so the output is 1.

Firing on document

Using document makes an event available anywhere.

Example

Example

javascript

document.addEventListener("themeChanged", function (event) {
  console.log("theme is now " + event.detail);
});

document.dispatchEvent(new CustomEvent("themeChanged", { detail: "dark" }));

detail can be any value, not only an object.

Why Bother?

It keeps parts of your code from having to know about each other.

One part announces what happened; others decide whether to care.

Example

Example

javascript

document.body.innerHTML = '<div id="cart"></div>';

const cart = document.getElementById("cart");
const log = [];

cart.addEventListener("itemAdded", function () { log.push("update the badge"); });
cart.addEventListener("itemAdded", function () { log.push("show a message"); });

cart.dispatchEvent(new CustomEvent("itemAdded", { detail: { name: "Book" } }));

console.log(log.join(" / "));

Adding a third response needs no change to the code that fires the event.

A Plain Event Works Too

Event is enough when you have no data to send.

Example

Example

javascript

document.body.innerHTML = '<div id="box"></div>';

const box = document.getElementById("box");

box.addEventListener("refresh", function () {
  console.log("refreshing");
});

box.dispatchEvent(new Event("refresh"));

CustomEvent is only needed for the detail property.

Complete Example

Complete Example

html

<!DOCTYPE html>
<html>
<head>
  <title>JavaScript Custom Events</title>
</head>
<body>

  <h1>Custom Events</h1>

  <button id="add">Add to cart</button>

  <p id="badge">Items: 0</p>
  <p id="message"></p>

  <script>
    const cart = document.getElementById("add");
    let count = 0;

    cart.addEventListener("click", function () {
      count = count + 1;
      cart.dispatchEvent(new CustomEvent("itemAdded", {
        detail: { name: "Book", total: count }
      }));
    });

    cart.addEventListener("itemAdded", function (event) {
      document.getElementById("badge").textContent = "Items: " + event.detail.total;
    });

    cart.addEventListener("itemAdded", function (event) {
      document.getElementById("message").textContent = "Added " + event.detail.name;
    });
  </script>

</body>
</html>

Try It Yourself

Run the above example in the Try It Editor.

Try a third listener:

Add another itemAdded listener and see it run as well.

Important Points

  • CustomEvent creates an event of your own.
  • detail carries data to the handler.
  • dispatchEvent fires it on an element.
  • Custom events do not bubble unless bubbles: true is set.
  • Use plain Event when there is no data to send.

Conclusion

Custom events let separate parts of your code communicate without being tied together.

They use exactly the same listening mechanism as built-in events.

This is a genuinely useful pattern once an application grows.