A journey to writing vanilla web components
Part 3: Events
If you come from the React world, it’s kind of the equivalent of callback props
Write a completely useless − yet experimental − component <events-demo />
The specs:
- Emit the event
'change'
using a button - Emit a custom event
'sayhello'
using another button - Be able to use listeners shorthand
.onchange
and.onsayhello
.

The template (HTML)
First, let’s start with our web component template:
<!-- index.html -->
<body>
<template id="events-demo-template">
<div>
<button id="dispatch-change">
Trigger change Event
</button>
</div>
<div>
<button id="dispatch-sayhello">
Trigger custom event "sayhello"
</button>
</div>
<style>…</style>
</template>
…
</body>
The component constructor
Now let’s see how we can dispatch those events using our buttons:
As always, let’s start with the boilerplate:
// events-demo.js
…export class HTMLEventsDemoElement extends HTMLElement {
constructor () {
super();
const template = document.getElementById(
"events-demo-template"
);
if (!template) {
throw new Error("<events-demo /> template is not defined");
}
this.attachShadow({ mode: "open" });
this.shadowRoot.appendChild(template.content.cloneNode(true));
…
}
}
Now that we are settled, let’s add methods to dispatch our events “change” and “sayhello”:
// events-demo.js
…export class HTMLEventsDemoElement extends HTMLElement {
constructor () {…} dispatchChange () {
this.dispatchEvent(new Event('change'));
} dispatchSayHello (detail = '') {
const customEvent = new CustomEvent('sayhello', { detail });
this.dispatchEvent(customEvent);
if (this.onsayhello) this.onsayhello(customEvent);
}
}
And finally, let’s trigger those events when the user clicks on a button:
// events-demo.js
…export class HTMLEventsDemo extends HTMLElement {
constructor () {
…
this.shadowRoot
.querySelector("button#dispatch-change")
.addEventListener("click", () => {
this.dispatchChange();
}); this.shadowRoot
.querySelector("button#dispatch-sayhello")
.addEventListener("click", () => {
this.dispatchSayHello("Hello from the other side…");
});
} …
}
Aand we’re done !

Using our component

Now we can use our component <events-demo />
and add event listeners to it, using JS. Check out the demo: