- Bind methods to DOM events with
data-on:event="method" - Handle keyboard events: Enter, Escape, arrow keys
- Emit custom
dv:*events withthis.emit() - Listen to external events with
this.listen() - Pass event data via
detail
data-on:* — the event directive
Bind component methods to DOM events directly in templates. The base class handles delegation:
template() {
return html`
<button data-on:click="increment">+</button>
<button data-on:click="decrement">−</button>
<input data-on:input="handleInput" value="${this.state.text}">
`;
}
increment() { this.state.count += 1; }
decrement() { this.state.count -= 1; }
handleInput(event) { this.state.text = event.target.value; }
The handler receives the native DOM event. this inside the handler is the component instance.
Keyboard events
Handle key presses for accessibility and UX patterns:
template() {
return html`
<input data-on:keydown="handleKeydown" placeholder="Type and press Enter">
<p>Last key: ${this.state.lastKey}</p>
`;
}
handleKeydown(event) {
this.state.lastKey = event.key;
if (event.key === 'Enter') {
this.state.submitted = this.state.text;
}
if (event.key === 'Escape') {
this.reset();
}
}
this.emit() — sending events outward
Emit custom events that parent components or page scripts can listen to. All events are prefixed with dv::
increment() {
this.state.count += 1;
this.emit('change', { count: this.state.count });
// Dispatches: new CustomEvent('dv:change', { detail: { count: 5 }, bubbles: true })
}
Page scripts listen with standard addEventListener:
document.querySelector('dv-counter')
.addEventListener('dv:change', (e) => {
console.log('Counter changed to', e.detail.count);
});
Bubbling by default
this.emit() creates bubbling events. Parent elements and the document can catch them. The dv: prefix makes the namespace clear.
this.listen() — safe external listeners
Listen to events on external targets (window, document, other DOM elements). The listener is automatically removed when the component disconnects:
connected() {
this.listen(window, 'resize', this.handleResize);
this.listen(document, 'scroll', this.handleScroll);
this.listen(someElement, 'custom-event', this.handleCustom);
}
handleResize() {
this.state.viewportWidth = window.innerWidth;
this.requestUpdate();
}
No need to manually call removeEventListener in disconnected().
Live demo: Event playground
Event naming conventions
| Pattern | Example | When |
|---|---|---|
| State change | dv:change | Counter, toggle, any value mutation |
| Selection | dv:select, dv:tab | User picks an item or tab |
| Lifecycle | dv:open, dv:close | Modal, dropdown, disclosure |
| User action | dv:confirm, dv:cancel | Explicit yes/no decisions |
| Query | dv:query | Search input changes |
Recap
data-on:* for DOM events
Bind methods to click, input, keydown, and any native event.
this.emit() for outward events
Tell the page what happened. Pages own persistence.
this.listen() for external
Auto-cleaned listeners on window/document/other elements.
dv:* namespace
All component events use the dv: prefix for clarity.