--- title: "createEventListener()" description: "Subscribe to DOM events with delegation, without decorators." group: Helpers order: 4 --- # createEventListener `createEventListener` subscribes to DOM events with delegation, window, or document targeting. It is the functional equivalent of the [`@onEvent`](/docs/decorators/on-event) decorator, designed for vanilla JS usage. Listeners are automatically attached on connect and detached on disconnect. The returned cleanup function permanently removes the listener. ## Usage ```typescript import { RadiantElement } from '@ecopages/radiant'; import { createEventListener } from '@ecopages/radiant/helpers/create-event-listener'; class ClickCounter extends RadiantElement { #count = 0; constructor() { super(); createEventListener(this, { selector: 'button', type: 'click' }, () => { this.#count++; console.log(`Clicked ${this.#count} times`); }); } } customElements.define('click-counter', ClickCounter); ``` Use it with authored light DOM: ```html ``` ## Parameters `createEventListener(host, config, callback)` accepts: | Parameter | Type | Required | Description | | :-------- | :--- | :------- | :---------- | | `host` | `RadiantElement` | Yes | The host element for lifecycle binding. | | `config` | `OnEventConfig` | Yes | Event configuration (see below). | | `callback` | `(event: Event) => void` | Yes | The event handler. | ### OnEventConfig — Target Selection (choose one) | Field | Type | Description | | :---- | :--- | :---------- | | `selector` | `string` | CSS selector for delegated matching. | | `ref` | `string` | Value of `data-ref` for delegated matching. | | `window` | `true` | Listen on the global `window` object. | | `document` | `true` | Listen on the global `document` object. | ### OnEventConfig — Event Options | Field | Type | Required | Description | | :---- | :--- | :------- | :---------- | | `type` | `string` | Yes | Event type (e.g., `'click'`, `'input'`, `'keydown'`). | | `options` | `AddEventListenerOptions` | No | Standard options like `{ passive: true, once: true }`. | ## Return Value Returns a `() => void` cleanup function. Calling it permanently removes the listener, even across reconnects. ```typescript const cleanup = createEventListener(host, { ref: 'btn', type: 'click' }, handler); // Later: permanently stop listening cleanup(); ``` ## Delegated Events When using `selector` or `ref`, the listener is delegated to the host element. Events bubble up from the target, and the handler fires only when `event.target` matches the selector. Because delegation relies on bubbling, it does not work with events that do not bubble (e.g., `focus`, `blur`). Use their bubbling alternatives (`focusin`, `focusout`). ## Window and Document Events ```typescript createEventListener( host, { window: true, type: 'scroll', options: { passive: true } }, () => console.log('scrolled'), ); createEventListener( host, { document: true, type: 'keydown' }, (event) => { if ((event as KeyboardEvent).key === 'Escape') { console.log('escape pressed'); } }, ); ``` ## Learn More - [`@onEvent`](/docs/decorators/on-event) — Decorator equivalent. - [`createEvent`](/docs/helpers/create-event) — Dispatch custom events. - [`debounce`](/docs/helpers/debounce) — Debounce frequent event handlers.