Skip to content
FrameworkJavaScript

Events API: subscribe to editor events

Subscribe to and manage editor lifecycle events.

Reaching the editor instance

The methods below run on the editor you created with new Blok(). They are available once editor.isReady resolves.

TypeScript
// You already hold the instance returned by the constructor.
const editor = new Blok({ holder: 'editor' });
await editor.isReady;

// Call any API method on it.
editor.caret.setToLastBlock('end');

Methods

on(event, callback)

void

Subscribe to an editor event.

When to use

Subscribe to editor lifecycle/content events. Keep a reference to the same callback so you can off() it later.

TypeScript
// Listen for block mutations — the callback receives the event payload,
// not an API object
editor.on('block changed', ({ event }) => {
  console.log('Block mutated:', event.type);
});

// Listen for individual block renders
editor.on('block:rendered', ({ blockId }) => {
  console.log('Rendered block:', blockId);
});

// Wait for a container block's child holders to settle before touching them.
// A React/Vue/Angular block renders through a portal that commits AFTER
// block:rendered, so a caret set in that window is dropped; this event fires
// once the holders are in the container's slot (it repeats on every later
// reconciliation pass — it is a settle signal, not a change signal).
const child = editor.blocks.insertInsideParent(containerId);

editor.on('block:childrenMounted', ({ blockId, childIds }) => {
  if (blockId === containerId && childIds.includes(child.id)) {
    editor.caret.setToBlock(child.id);
  }
});

// With the `collaboration` config on, this is the sync/presence indicator
// feed: status is 'connecting' | 'connected' | 'offline' | 'error', and peers
// lists everyone else in the document. 'offline' is still retrying (retryInMs
// says when) and local edits stay pending; 'error' has stopped for good and
// carries the reason. Single-player editors never emit it.
editor.on('collaboration:status', ({ status, peers }) => {
  console.log(status, peers.map((peer) => peer.user.name));
});

// To react to content changes with access to the API, use the
// onChange(api, event) config callback (async is allowed there):
//   onChange: async (api) => { const data = await api.save(); }

off(event, callback)

void

Unsubscribe from an editor event.

When to use

Pass the exact same function reference you subscribed with — anonymous inline callbacks can't be removed.

TypeScript
const handleRendered = (payload) => console.log('Rendered');
editor.on('block:rendered', handleRendered);

// Later, remove the listener (pass the same function reference)
editor.off('block:rendered', handleRendered);

emit(event, data)

void

Emit a custom event. Fire-and-forget over the listeners registered at that moment — there is no replay, so a handler subscribed after the emit never sees it.

When to use

For tools/plugins to broadcast custom events on the editor bus; app code usually listens with on() rather than emits.

TypeScript
// Subscribe first — an emit with no listener is simply dropped
editor.on('custom-event', (data) => {
  console.log(data.message); // 'Hello'
});

editor.emit('custom-event', { message: 'Hello', data: 123 });