Use event listeners
An event is a signal that something has happened on your page. The browser notifies you so you can react to them.
What are events?
From MDN
Events are things that happen in the system you are programming — the system produces (or “fires”) a signal of some kind when an event occurs, and provides a mechanism by which an action can be automatically taken (that is, some code running) when the event occurs. Events are fired inside the browser window, and tend to be attached to a specific item that resides in it. This might be a single element, a set of elements, the HTML document loaded in the current tab, or the entire browser window. There are many different types of events that can occur.
For example:
- A user submits a form
- A user clicks on a button
- A web page finishes loading
- etc.
Adding a click event listener
Suppose we have a simple web component called custom-button
that we want to add a click event listener to.
import CustomElement from '@enhance/custom-element'
export default class CustomButton extends CustomElement {
render ({ html, state }) {
return html`
<style>
button {
border: 1px solid white;
padding: 2px;
}
</style>
<button>Click me!</button>
`
}
}
customElements.define('custom-button', CustomButton)
As a best practice, event listeners for web components should be added inside the connectedCallback
function, since this method runs when the element is added to the DOM.
Inside our connectedCallback
method, we’ll use the querySelector
method on the custom element, to get the button inside our component. Then we will add a click
listener to the button.
import CustomElement from '@enhance/custom-element'
export default class CustomButton extends CustomElement {
connectedCallback () {
this.button = this.querySelector('button')
this.button.addEventListener('click', function (event) {
alert('I was clicked')
})
}
render ({ html, state }) {
return html`
<style>
button {
border: 1px solid white;
padding: 2px;
}
</style>
<button>Click me!</button>
`
}
}
customElements.define('custom-button', CustomButton)
That works great, but if we want to follow best practices, we should clean up our event listeners when our component is removed from the DOM. We’ll remove that event listener in the disconnectedCallback
method. In order to do that, we’ll need to refactor our component slightly.
- Extract our click handler to a method named
clickHander
. - Save a reference to the
button
element in theconstructor
. - Bind
this
to the callback function. - Add the event listener in
connectedCallback
. - Remove the event listener in
disconnectedCallback
.
import CustomElement from '@enhance/custom-element'
export default class CustomButton extends CustomElement {
constructor () {
super()
this.button = this.querySelector('button')
this.handleClick = this.handleClick.bind(this)
}
handleClick (event) {
alert('I was clicked')
}
connectedCallback () {
this.button.addEventListener('click', this.handleClick)
}
disconnectedCallback () {
this.button.removeEventListener('click', this.handleClick)
}
render ({ html, state }) {
return html`
<style>
button {
border: 1px solid white;
padding: 2px;
}
</style>
<button>Click me!</button>
`
}
}
customElements.define('custom-button', CustomButton)
If the bind
method offends you, then you can always use a public class field and an arrow function instead.
handleClick = (event) => {
alert('I was clicked')
}
Reducing Boilerplate
Many web component libraries provide a way of reducing boilerplate when authoring web components. Enhance provides the @enhance/element
package, which builds upon the CustomElement
and EventHandlerMixin
classes while providing a more succinct way of writing Enhance Components.
Revisiting our custom-button
component we get:
import enhance from '@enhance/element'
const CustomButton = {
render ({ html, state }) {
return html`
<style>
button {
border: 1px solid white;
padding: 2px;
}
</style>
<button>Click me!</button>
`
},
click (event) {
alert('I was clicked')
}
}
enhance('custom-button', CustomButton)
export default CustomButton
Add an attribute with a valid event name ( i.e. “click” ) to your custom element markup then and a function of the same name in your Web Component class and it will get called when a user interaction triggers the event.
<custom-button click></custom-button>
Optionally, you can target your event listener by passing in the value of the child element. For example:
<custom-button click="button"></custom-button>