Documentation Index Fetch the complete documentation index at: https://empty-ad9a3406.mintlify.app/llms.txt
Use this file to discover all available pages before exploring further.
Two Mechanisms
Events Hooks Purpose Notify Extend Return values No Yes Use case ”Something happened" "Add your thing to my thing”
Events (Pub/Sub)
Emitting
api . bus . emit ( 'todo:added' , { text: 'Buy milk' , count: 3 });
Listening
api . bus . on ( 'todo:added' , ( data ) => {
console . log ( `Total todos: ${ data . count } ` );
});
One-Shot Listening
// Fires once, then auto-removes
api . bus . once ( 'board:ready' , ( data ) => {
console . log ( 'Board ready, only fires once' );
});
Unsubscribing
function handler ( data ) { /* ... */ }
api . bus . on ( 'my-event' , handler );
// Later:
api . bus . off ( 'my-event' , handler ); // Must be same reference
Full Example
// === Plugin A: todo-list ===
export function setup ( api ) {
const todos = [];
function add ( text ) {
todos . push ({ text , done: false });
api . bus . emit ( 'todo:added' , { text , count: todos . length });
}
function toggle ( index ) {
todos [ index ]. done = ! todos [ index ]. done ;
api . bus . emit ( 'todo:toggled' , { index , done: todos [ index ]. done });
}
}
// === Plugin B: stats ===
export function setup ( api ) {
let total = 0 ;
let completed = 0 ;
api . bus . on ( 'todo:added' , ( data ) => {
total = data . count ;
render ();
});
api . bus . on ( 'todo:toggled' , ( data ) => {
completed += data . done ? 1 : - 1 ;
render ();
});
}
Hooks (Extension Points)
Registering
// Toolbar plugin exposes an extension point
api . registerHook ( 'sidebar:add-section' , ( config ) => {
const section = document . createElement ( 'div' );
section . innerHTML = `<h4> ${ config . title } </h4>` ;
sidebar . appendChild ( section );
return section ;
});
Using
// Another plugin adds a section to the sidebar
const sections = api . useHook ( 'sidebar:add-section' , {
title: 'My Section' ,
content: 'Hello from my plugin!'
});
// sections → [sectionElement, ...]
Removing
function myHandler ( config ) { /* ... */ }
api . registerHook ( 'my-hook' , myHandler );
// Later (e.g., in teardown):
api . removeHook ( 'my-hook' , myHandler );
Full Example
// === Plugin A: toolbar ===
export function setup ( api ) {
const toolbar = document . createElement ( 'div' );
toolbar . style . cssText = 'display:flex; gap:8px; padding:12px;' ;
api . registerHook ( 'toolbar:add-button' , ( config ) => {
const btn = document . createElement ( 'button' );
btn . textContent = config . label ;
btn . onclick = config . action ;
toolbar . appendChild ( btn );
return btn ;
});
// Invoke hooks after all plugins are loaded
api . bus . once ( 'board:allPluginsLoaded' , () => {
api . useHook ( 'toolbar:add-button' , {
label: '🏠 Home' ,
action : () => goHome ()
});
});
api . boardEl . appendChild ( toolbar );
}
// === Plugin B: my-tools ===
export function setup ( api ) {
// Wait for toolbar to register its hook
api . bus . once ( 'board:allPluginsLoaded' , () => {
api . useHook ( 'toolbar:add-button' , {
label: '📊 Stats' ,
action : () => showStats ()
});
api . useHook ( 'toolbar:add-button' , {
label: '⚙️ Settings' ,
action : () => openSettings ()
});
});
}
Reacting to Lifecycle Events
After All Plugins Load
Use board:allPluginsLoaded when your plugin depends on other plugins being ready:
export function setup ( api ) {
// Register my hooks immediately
api . registerHook ( 'my-plugin:add-item' , ( config ) => { /* ... */ });
// Use other plugins' hooks after they're all loaded
api . bus . once ( 'board:allPluginsLoaded' , () => {
api . useHook ( 'toolbar:add-button' , {
label: 'My Action' ,
action : () => doSomething ()
});
});
}
Listening to Other Plugins’ Events
// React when a sticky note is created
api . bus . on ( 'sticky-note:created' , ({ id }) => {
api . notify ( `New note created: ${ id } ` , 'info' );
});
// React when a clock ticks
api . bus . on ( 'clock:tick' , ({ hours , minutes }) => {
if ( hours === 0 && minutes === 0 ) {
api . notify ( 'Midnight!' , 'warning' );
}
});
Best Practices
Don't import other plugins
Always use events or hooks — never import('./other-plugin.js').
Use namespaced event names
my-plugin:action not action.
Remove event listeners and hooks in your teardown() function: function handler ( data ) { /* ... */ }
export function setup ( api ) {
api . bus . on ( 'my-event' , handler );
api . registerHook ( 'my-hook' , myHandler );
}
export function teardown () {
api . bus . off ( 'my-event' , handler );
api . removeHook ( 'my-hook' , myHandler );
}
Use `once` for one-time setup
api . bus . once ( 'board:ready' , () => {
// Initialization that should only happen once
});