Instance events
Everything an instance dispatches is a real DOM event, so a plain addEventListener hears all of it.
Component events
$emit(name, payload?) dispatches on $el:
| Property | Value |
|---|---|
bubbles | true |
cancelable | true |
detail | the payload object, or null |
Names are typed lower-kebab string literals declared through the props type's $emits key. There is no namespace: a component event is open, not js-toolkit:open.
el.addEventListener('goto', (event) => {
console.log(event.detail.index);
});Lifecycle announcements
Every instance announces its own mount and unmount, carrying itself in the payload:
interface LifecycleEventDetail {
instance: Base;
}| Event | Constant | Dispatched from |
|---|---|---|
js-toolkit:component:mounted | EVENTS.component.mounted | the element — bubbles |
js-toolkit:component:unmounted | EVENTS.component.unmounted | document |
import { EVENTS, type LifecycleEventDetail } from '@studiometa/js-toolkit';
document.addEventListener(EVENTS.component.mounted, (rawEvent) => {
const event = rawEvent as CustomEvent<LifecycleEventDetail>;
console.log(`${event.detail.instance.$id} mounted`);
});The unmount event dispatches from document because the element can already be detached. That is also what lets one lazy, realm-shared listener serve every $watchChildren() watcher while the document holds nothing but weak references to them — a listener per watcher would make every watching component immortal.
An instance that is scheduled but not mounted announces nothing.
Diagnostics
js-toolkit:diagnostic — EVENTS.diagnostic — starts on the relevant connected element, or on document when there is none, with { bubbles: true, composed: true, cancelable: true }.
preventDefault() suppresses the default console output only. See Diagnostics.
Negotiated events
js-toolkit:dom:update — EVENTS.dom.update — is dispatched by domUpdate(), and emitExtendable() dispatches the name its caller gives.
Both are bubbling and non-cancelable: the step is announced, not proposed. Their detail carries a wrap() or a waitUntil() valid only while the event dispatches.
They have no Base path and are absent from $emits, so the negotiation code and the optional view-transition import stay out of the Base graph. Plain DOM code uses the same functions with no instance.
Private transports
The context request is a bubbling, module-private event and is deliberately not part of public EVENTS. Framework internals that need a transport use module-local namespaced constants; only what a consumer can usefully listen to is exported.
The convention, in full
- Public framework events use the deeply frozen
EVENTSobject and thejs-toolkit:namespace. - Private framework transports use module-local constants and do not join
EVENTS. - Component events use typed lower-kebab string literals from
$emits. - A payload is one object in
CustomEvent.detail, or the platform valuenull. - Diagnostic events are cancelable, so monitoring can suppress the default output only.