In Jurassic Park, different systems must cooperate - the dinosaur monitoring system must inform the security center about threats, and the security center must notify rescue teams. Standard browser events (click, keydown, submit) handle user interactions, but what if we need custom messages between application modules? This is where Custom Events come to the rescue - custom, non-standard events.
The
CustomEvent constructor allows you to create an event with any name and pass additional data through the detail property:1// Syntax: new CustomEvent(eventName, options)
2const alertEvent = new CustomEvent('dinoAlert', {
3 detail: {
4 species: 'Velociraptor',
5 zone: 'B6',
6 threatLevel: 9
7 },
8 bubbles: true, // Whether the event bubbles up the DOM tree
9 cancelable: true // Whether it can be canceled via preventDefault()
10});The
detail property can contain any data - objects, arrays, strings, numbers. This is the main difference between CustomEvent and a regular Event, which doesn't have a detail field.To "fire" an event, we use the
dispatchEvent() method on any DOM element:1// Dispatching an event on a specific element
2const monitorPanel = document.getElementById('monitor-panel');
3monitorPanel.dispatchEvent(alertEvent);
4
5// Dispatching an event on the entire document (global broadcast)
6document.dispatchEvent(alertEvent);When an event is dispatched, all registered listeners for it are called synchronously - in the order they were registered.
Listening for Custom Events works identically to standard events - using
addEventListener():1// Listening on any element
2document.addEventListener('dinoAlert', function(event) {
3 const { species, zone, threatLevel } = event.detail;
4
5 console.log(`ALERT: ${species} detected in zone ${zone}!`);
6 console.log(`Threat level: ${threatLevel}/10`);
7
8 if (threatLevel >= 8) {
9 activateEmergencyProtocol(zone);
10 }
11});Let's combine all elements into a complete inter-module communication system:
1// Module 1: Alert generator
2function createParkAlert(alertType, message, data = {}) {
3 const alertEvent = new CustomEvent('parkAlert', {
4 detail: {
5 type: alertType,
6 message: message,
7 timestamp: new Date(),
8 data: data
9 },
10 bubbles: true
11 });
12
13 document.dispatchEvent(alertEvent);
14}
15
16// Module 2: Central listening system
17document.addEventListener('parkAlert', (e) => {
18 const { type, message, timestamp, data } = e.detail;
19
20 console.log(`${timestamp.toLocaleTimeString()} - Alert ${type}: ${message}`);
21
22 switch(type) {
23 case 'security':
24 showSecurityAlert(message, data);
25 break;
26 case 'maintenance':
27 showMaintenanceNotification(message, data);
28 break;
29 case 'visitor':
30 showVisitorInfo(message, data);
31 break;
32 default:
33 showGeneralAlert(message);
34 }
35});
36
37// Module 3: Dinosaur escape detection
38function handleDinosaurEscape(dinosaurId) {
39 const dinosaur = getDinosaurById(dinosaurId);
40
41 createParkAlert('security', `ALARM! ${dinosaur.name} escaped from the enclosure!`, {
42 dinosaurId: dinosaurId,
43 location: dinosaur.enclosure,
44 dangerLevel: dinosaur.dangerLevel
45 });
46
47 activateEmergencyProtocols();
48}Custom Events allow you to build a simple Event Bus - a central communication point between independent application modules:
1class ParkEventBus {
2 constructor() {
3 this.target = new EventTarget();
4 }
5
6 emit(eventName, data) {
7 this.target.dispatchEvent(
8 new CustomEvent(eventName, { detail: data })
9 );
10 }
11
12 on(eventName, callback) {
13 const handler = (e) => callback(e.detail);
14 this.target.addEventListener(eventName, handler);
15 // Return a function to unsubscribe
16 return () => this.target.removeEventListener(eventName, handler);
17 }
18}
19
20const bus = new ParkEventBus();
21
22// Monitoring module subscribes to alerts
23const unsubscribe = bus.on('fenceBreak', (data) => {
24 console.log(`Fence in zone ${data.zone} damaged!`);
25});
26
27// Sensor module sends alert
28bus.emit('fenceBreak', { zone: 'C3', voltage: 0 });
29
30// When the module is destroyed - unsubscribe
31unsubscribe();Thanks to Event Bus, modules don't need to know about each other - they communicate exclusively through events, which ensures loose coupling and easier testing.