Appearance
Events
Generative DOM includes an event system that allows plugins to communicate with application code and with each other. This guide covers subscribing to events, emitting events from plugins, and the event lifecycle.
Subscribing to Events
Use md.on() to subscribe to events and md.off() to unsubscribe:
ts
const handler = (data: unknown) => {
console.log('Progress:', data);
};
md.on('events:progress', handler);
// Later, unsubscribe:
md.off('events:progress', handler);Event names are namespaced by plugin name. When a plugin named events calls ctx.emit('progress', data), subscribers receive it as events:progress.
Event Flow
Plugin calls ctx.emit("progress", { value: 35 })
|
v
Core namespaces it: "events:progress"
|
v
Core dispatches to all handlers registered via md.on("events:progress", handler)
|
v
Handler receives: { value: 35 }Event Guarantees
- Events are dispatched synchronously in listener registration order.
- If a listener throws, other listeners still execute. The error is logged via
console.error, not propagated. - Events emitted during
render()are dispatched immediately, before the next token is rendered.
The Events Plugin
The events plugin parses invisible elements from the stream that produce no DOM output but emit events:
markdown
<progress value="35" max="100" />
<status type="complete" />
<milestone name="section-1" />These elements are consumed by the parser and produce events, but nothing is added to the DOM.
Event Payloads
ts
// <progress value="35" max="100" />
md.on('events:progress', (data) => {
// data: { value: 35, max: 100 }
});
// <status type="complete" />
md.on('events:status', (data) => {
// data: { type: "complete" }
});
// <milestone name="section-1" />
md.on('events:milestone', (data) => {
// data: { name: "section-1" }
});Mixing Events with Markdown
Event elements can appear inline with regular markdown:
markdown
Hello <progress value="50" max="100" /> worldThis renders "Hello world" in the DOM while emitting a progress event between parsing the two text segments.
Interactive Element Events
The interactive plugin emits events when users interact with rendered elements:
ts
md.on('interactive:button-click', (data) => {
// data: { text: "Click me", clickCount: 3 }
});
md.on('interactive:toggle', (data) => {
// data: { label: "Dark mode", checked: true }
});
md.on('interactive:input-change', (data) => {
// data: { value: "typed text" }
});Plugin-to-Plugin Communication
Plugins can check for each other's presence via PluginContext.getPlugin():
ts
init(ctx: PluginContext) {
const codePlugin = ctx.getPlugin('markdown-code');
if (codePlugin) {
// The code plugin is registered; adjust behavior accordingly
}
}Plugins must not call methods on other plugins directly -- only check presence and read name/priority.