JavaScript in the browser

Custom events in JavaScript

Learn how to create and dispatch custom events in JavaScript, using the Event and CustomEvent objects in the browser and the EventEmitter class in Node.js.

Built-in events cover clicks, keys, and network lifecycle signals. You can also define your own custom events when components need to talk without tight coupling.

In the browser, start with Event:

const anEvent = new Event('start');

Dispatch it on a target:

document.dispatchEvent(anEvent)

Register a listener separately:

document.addEventListener('start', event => {   
  console.log('started!')
})

Pass extra data with CustomEvent:

const anotherEvent = new CustomEvent('start', {
  detail: {
    color: 'white'
  }
})

Read that payload as event.detail:

document.addEventListener('start', event => {   
  console.log('started!')
  console.log(event.detail)
})

On the server, Node.js uses the events module:

const EventEmitter = require('events')
const eventEmitter = new EventEmitter()
  • emit fires an event
  • on registers a handler
eventEmitter.on('start', () => {
  console.log('started')
})
eventEmitter.emit('start')

Pass arguments through emit:

eventEmitter.on('start', (number) => {
  console.log(`started ${number}`)
})

eventEmitter.emit('start', 23)

Multiple arguments:

eventEmitter.on('start', (start, end) => {
  console.log(`started from ${start} to ${end}`)
})

eventEmitter.emit('start', 1, 100)

Dispatch a CustomEvent in the browser console and confirm the listener logs both started! and your detail object.

Custom events decouple pieces of a page: a widget can announce save without knowing every listener that reacts to it.

In Node, many core modules extend EventEmitter. The idea matches browser events, but the API surface is different.

Browser CustomEvent payloads must live on detail. Node passes arbitrary arguments to the handler through emit().

Name custom events like built-ins: lowercase, no spaces, often with a namespace prefix such as app:save when several features share one bus.

Dispatch on the smallest target that makes sense. A widget can dispatch on its root element instead of document when only that subtree should react.

Browser listeners and Node EventEmitter handlers both decouple producers from consumers. Pick the API your runtime gives you.

Register the listener before you dispatch, or the event will fire with no handler attached.

Run the browser examples in order: add the listener, dispatch, then read event.detail from the handler log.

The same pattern works on element.dispatchEvent() when only part of the page should hear the event.

Lesson completed