Learn Development at Frontend Masters
An event bus is a design pattern (and while we’ll be talking about JavaScript here, it’s a design pattern in any language) that can be used to simplify communications between different components. It can also be thought of as publish/subscribe or pubsub.
The idea is that components can listen to the event bus to know when to do the things they do. For example, a “tab panel” component might listen for events telling it to change the active tab. Sure, that might happen from a click on one of the tabs, and thus handled entirely within that component. But with an event bus, some other elements could tell the tab to change. Imagine a form submission which causes an error that the user needs to be alerted to within a specific tab, so the form sends a message to the event bus telling the tabs component to change the active tab to the one with the error. That’s what it looks like aboard an event bus.
Pseudo-code for that situation would be like…
Do you need a JavaScript library to this? (Trick question: you never need a JavaScript library). Well, there are lots of options out there:
Also, check out Mitt which is a library that’s only 200 bytes gzipped. There is something about this simple pattern that inspires people to tackle it themselves in the most succincet way possible.
Let’s do that ourselves! We’ll use no third-party library at all and leverage an event listening system that is already built into JavaScript with the addEventListener
we all know and love.
The addEventListener
API in JavaScript is a member function of the <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget">EventTarget</a>
class. The reason we can bind a click
event to a button is because the prototype interface of <button>
(<a href="https://developer.mozilla.org/en-US/docs/Web/API/HTMLButtonElement">HTMLButtonElement</a>
) inherits from EventTarget
indirectly.
Different from most other DOM interfaces, EventTarget
can be created directly using the new
keyword. It is supported in all modern browsers, but only fairly recently. As we can see in the screenshot above, Node
inherits EventTarget
, thus all DOM nodes have method addEventListener
.
I’m suggesting an extremely lightweight Node
type to act as our event-listening bus: an HTML comment (<!--
comment
-->
).
To a browser rendering engine, HTML comments are just notes in the code that have no functionality other than descriptive text for developers. But since comments are still written in HTML, they end up in the DOM as real nodes and have their own prototype interface—<a href="https://developer.mozilla.org/en-US/docs/Web/API/Comment">Comment</a>
—which inherits Node
.
The Comment
class can be created from new
directly like EventTarget
can:
We could also use the ancient, but widely-supported <a href="https://developer.mozilla.org/en-US/docs/Web/API/Document/createComment">document.createComment</a>
API. It requires a data
parameter, which is the content of the comment. It can even be an empty string:
Now we can emit events using <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/dispatchEvent">dispatchEvent</a>
, which accepts an Event
Object. To pass user-defined event data, use <a href="https://developer.mozilla.org/en-US/docs/Web/API/CustomEvent/">CustomEvent</a>
, where the detail
field can be used to contain any data.
Internet Explorer 9-11 supports CustomEvent
, but none of the versions support new CustomEvent
. It’s complex to simulate it using document.createEvent
, so if IE support is important to you, there’s a way to polyfill it.
Now we can bind event listeners:
If an event intends to be triggered only once, we may use { once: true }
for one-time binding. Other options won’t fit here. To remove event listeners, we can use the native <a href="https://developer.mozilla.org/en-US/docs/Web/API/EventTarget/removeEventListener">removeEventListener</a>
.
The number of events bound to single event bus can be huge. There also can be memory leaks if you forget to remove them. What if we want to know how many events are bound to myEventBus
?
myEventBus
is a DOM node, so it can be inspected by DevTools in the browser. From there, we can find the events in the Elements → Event Listeners tab. Be sure to uncheck “Ancestors” to hide events bound on document
and window
.
One drawback is that the syntax of EventTarget
is slightly verbose. We can write a simple wrapper for it. Here is a demo in TypeScript below:
The following demo provides the compiled JavaScript.
And there we have it! We just created a dependency-free event-listening bus where one component can inform another component of changes to trigger an action. It doesn’t take a full library to do this sort of stuff, and the possibilities it opens up are pretty endless.
Frontend Masters is the best place to get it. They have courses on all the most important front-end technologies, from React to CSS, from Vue to D3, and beyond with Node.js and Full Stack.
Frontend Masters is the best place to get it. They have courses on all the most important front-end technologies, from React to CSS, from Vue to D3, and beyond with Node.js and Full Stack.
Cool 🙂
You can think of event bus as hooks in WordPress. This one uses native JavaScript, but doesn’t use the Event API so it supports more browsers. Suitable to be extended in a tiny application:
https://github.com/taufik-nurrohman/hook
You may write comments in Markdown thanks to Jetpack Markdown. This is the best way to post any code, inline like `<div>this</div>` or multiline blocks within triple backtick fences (“`) with double new lines before and after. All comments are held for moderation. Be helpful and kind and yours will be published no problem.
The related posts above were algorithmically generated and displayed here without any load on my server at all, thanks to Jetpack.
CSS-Tricks* is created, written by, and maintained by Chris Coyier and a team of swell people. The tech stack for this site is fairly boring. That’s a good thing! I’ve used WordPress since day one all the way up to v17, a decision I’m very happy with. I also leverage Jetpack for extra functionality and Local for local development.
*May or may not contain any actual “CSS” or “Tricks”.
CodePen is a place to experiment, debug, and show off your HTML, CSS, and JavaScript creations.
CSS-Tricks is hosted by Flywheel, the best WordPress hosting in the business, with a local development tool to match.
ShopTalk is a podcast all about front-end web design and development.