eventtarget
js/globals/eventtarget.ts
Event, CustomEvent, and EventTarget globals.
Pure JS implementation of the WHATWG EventTarget interface: https://dom.spec.whatwg.org/#interface-eventtarget
Scope: flat dispatch only (no DOM tree). All events fire at AT_TARGET.
The bubbles and composed flags are stored but have no propagation
effect — Fino has no parent node traversal.
Spec conformance:
- addEventListener is idempotent for the same (callback, capture) pair
- once: true auto-removes the listener after first invocation
- signal option auto-removes the listener when the AbortSignal aborts
- passive listeners cannot cancel the event via preventDefault()
- dispatchEvent throws if the event is currently being dispatched
- Listener errors are swallowed and do not prevent later listeners from
firing. Fino does not currently report these through a browser-style
global error event.
Example
const target = new EventTarget();
target.addEventListener('ready', () => console.log('ready'), { once: true });
target.dispatchEvent(new Event('ready'));
target.dispatchEvent(new Event('ready'));
Types
type EventCallback = ((event: Event) => void) | {
handleEvent(event: Event): void;
}
Event listener callback accepted by EventTarget.addEventListener().
A listener can be a function or an object with a handleEvent() method.
Both forms receive the dispatched Event instance.
const listener: EventCallback = (event) => console.log(event.type);
target.addEventListener('ready', listener);
Interfaces
interface AddEventListenerOptions {
Options accepted by EventTarget.addEventListener().
capture participates in listener identity for compatibility, but Fino has
no DOM tree and dispatches every event at the target. once removes the
listener after the first call. passive prevents preventDefault() from
canceling the event while that listener runs. signal removes the listener
when the supplied AbortSignal aborts.
target.addEventListener('message', onMessage, {
once: true,
signal: controller.signal,
});
Properties
capture?: boolean
Participates in listener identity (a listener is uniquely keyed by callback plus capture flag) but has no traversal effect in Fino's flat dispatch.
once?: boolean
When true, the listener is removed automatically after its first invocation.
passive?: boolean
When true, preventDefault() is a no-op while this listener runs, so the
listener cannot cancel the event.
signal?: AbortSignal
An AbortSignal that removes the listener when it aborts. A signal that is
already aborted skips registration entirely; passing null throws.
Classes
class Event {
Flat-dispatch implementation of the WHATWG Event interface.
Fino does not have a DOM tree, so every dispatch runs at AT_TARGET and composedPath() returns either the dispatch target or an empty array.
const event = new Event('ready', { cancelable: true });
event.type; // "ready"
Static Properties
static NONE
Event phase constant for no active dispatch.
Event.NONE; // 0
static CAPTURING_PHASE
Event phase constant for DOM capture.
Fino stores the value for compatibility but never enters this phase because there is no parent tree.
Event.CAPTURING_PHASE; // 1
static AT_TARGET
Event phase constant used while dispatching to the target.
Event.AT_TARGET; // 2
static BUBBLING_PHASE
Event phase constant for DOM bubbling.
The value is exposed for compatibility, but Fino never bubbles events.
Event.BUBBLING_PHASE; // 3
Constructors
constructor(type: string, eventInitDict?: {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
})
Create an Event with optional bubbles, cancelable, and composed flags.
The type argument is required and string-coerced. The flags are stored for compatibility, but bubbles and composed do not cause propagation in this flat EventTarget implementation.
const event = new Event('submit', { cancelable: true });
event.cancelable; // true
Getters
get type()
Event type supplied at construction or initEvent().
new Event('message').type; // "message"
get bubbles()
Whether the event was constructed with bubbles: true.
This flag is stored only; Fino has no bubbling tree.
new Event('x', { bubbles: true }).bubbles; // true
get cancelable()
Whether preventDefault() can set defaultPrevented.
Passive listeners cannot cancel even when this is true.
new Event('x', { cancelable: true }).cancelable; // true
get composed()
Whether the event was constructed with composed: true.
This value is exposed for compatibility and has no propagation effect.
new Event('x', { composed: true }).composed; // true
get defaultPrevented()
Whether preventDefault() has successfully canceled the event.
It remains false for non-cancelable events and inside passive listeners.
const event = new Event('x', { cancelable: true });
event.preventDefault();
event.defaultPrevented; // true
get target()
EventTarget currently dispatching or last dispatched this event.
The target is null before dispatch and preserved after dispatch, matching browser behavior.
const target = new EventTarget();
const event = new Event('x');
target.dispatchEvent(event);
event.target === target; // true
get currentTarget()
EventTarget whose listener is currently running.
This is set during dispatch and reset to null after dispatch completes.
const target = new EventTarget();
target.addEventListener('x', (event) => console.log(event.currentTarget));
get eventPhase()
Current dispatch phase.
Fino reports AT_TARGET during listener execution and NONE otherwise.
const event = new Event('x');
event.eventPhase; // Event.NONE
get timeStamp()
Monotonic timestamp captured when the Event was created.
Uses performance.now() when available, otherwise Date.now().
const event = new Event('x');
typeof event.timeStamp; // "number"
get isTrusted()
Whether the event was generated by the runtime rather than user code.
Events created with new Event(...) are untrusted. Built-in APIs may mark
their own spec-defined events as trusted before dispatch.
new Event('x').isTrusted; // false
Methods
preventDefault()
Mark a cancelable event as default-prevented.
Calling this on a non-cancelable event or from a passive listener has no effect.
const event = new Event('x', { cancelable: true });
event.preventDefault();
stopPropagation()
Request that event propagation stop after the current target.
With flat dispatch this flag is stored for compatibility but there are no ancestor targets to skip.
const event = new Event('x');
event.stopPropagation();
stopImmediatePropagation()
Stop dispatching any remaining listeners for this event.
During dispatch this prevents later listeners on the same EventTarget from running.
const target = new EventTarget();
target.addEventListener('x', (event) => event.stopImmediatePropagation());
composedPath()
Return the composed path for this event.
Because there is no DOM tree, the path is [target] while dispatching and
an empty array outside dispatch.
const event = new Event('x');
event.composedPath(); // []
class CustomEvent extends Event {
Event subclass that carries arbitrary detail data.
The detail value defaults to null and is stored by reference.
const event = new CustomEvent('data', { detail: { id: 1 } });
event.detail.id; // 1
Constructors
constructor(type: string, eventInitDict?: {
bubbles?: boolean;
cancelable?: boolean;
composed?: boolean;
detail?: unknown;
})
Create a CustomEvent with optional detail.
Event flags are passed through to Event. Missing detail becomes null.
const event = new CustomEvent('x', { detail: 'payload' });
event.detail; // "payload"
Getters
get detail()
Application-defined payload for the custom event.
new CustomEvent('x').detail; // null
Methods
initCustomEvent(
type: string,
bubbles: boolean = false,
cancelable: boolean = false,
detail: unknown = null
): void
Legacy initializer for CustomEvent instances.
Calls during dispatch are ignored. The method updates type, bubbles, cancelable, and detail.
const event = new CustomEvent('old');
event.initCustomEvent('new', false, false, 123);
class EventTarget {
WHATWG EventTarget with flat listener dispatch.
Listener registration is idempotent for the same callback and capture flag. Listener exceptions are swallowed so later listeners still run; this runtime does not surface those exceptions through a global error event.
const target = new EventTarget();
target.addEventListener('ready', () => console.log('ready'));
target.dispatchEvent(new Event('ready'));
Constructors
constructor()
Create an EventTarget with an empty listener registry.
const target = new EventTarget();
Methods
addEventListener(
type: string,
callback: EventCallback | null,
options?: boolean | AddEventListenerOptions
): void
Register an event listener.
Registration is idempotent: adding the same callback with the same capture
flag again is a no-op. Null callbacks and objects without a handleEvent
method are silently ignored, and a signal that is already aborted skips
registration entirely. The once option removes the listener after its
first invocation, passive prevents preventDefault() from canceling the
event while that listener runs, and signal removes the listener when the
AbortSignal aborts.
Throws if signal is explicitly null rather than an AbortSignal or
undefined — even when the callback is also null.
const target = new EventTarget();
target.addEventListener('tick', (event) => console.log(event.type), { once: true });
removeEventListener(type: string, callback: EventCallback, options?: boolean | {
capture?: boolean;
}): void
Remove a previously registered event listener.
The type, callback, and capture flag must match the original registration. Unknown listeners are ignored.
const target = new EventTarget();
const fn = () => {};
target.addEventListener('x', fn);
target.removeEventListener('x', fn);
dispatchEvent(event: Event): boolean
Dispatch an Event synchronously to matching listeners.
Listeners run in registration order against a snapshot taken at dispatch
time: listeners added during dispatch do not run for the current event,
while listeners removed during dispatch are skipped. Exceptions thrown by
listeners are swallowed so later listeners still run. Returns false only
when a cancelable event was canceled via preventDefault().
Throws if the argument is not an Event instance, or if the event is already being dispatched.
const target = new EventTarget();
const ok = target.dispatchEvent(new Event('x', { cancelable: true }));