Keyboard shortcuts

Press or to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

Event System

The event system is the primary communication mechanism between runtime services, plugins, and UI components. Almost every class in the API package extends EventDispatcher.

EventDispatcher

EventDispatcher<EventTypes> (packages/api/src/lib/events.ts) wraps EventEmitter3:

Methods

MethodPurpose
on(eventName, listener, context?)Subscribe. Returns EventRef for manual unsubscription.
once(eventName, listener, context?)One-time subscription.
off(eventName, listener, context?, once?)Unsubscribe by function reference.
offref(ref: EventRef)Unsubscribe using ref.
trigger(eventName, ...args)Emit event.
emit(eventName, ...args)Alias for trigger.
dispatch(eventName, ...args)Alias for trigger.
tryTrigger(ref, ...args)Safe trigger that catches errors.

Type System

Events are fully typed via a generic map:

class MyService extends EventDispatcher<{
  "file-change": [file: TFile, event: string];
  "load": [];
}> {}

const ref = service.on("file-change", (file, event) => { ... });
service.offref(ref);  // Clean up

Lifecycle Integration

Component.registerEvent(ref) tracks event subscriptions and automatically unsubscribes them when the component is unloaded. This prevents memory leaks in views and plugins.

// In a Plugin or View:
this.registerEvent(
  app.vault.on("modify", (file) => { ... })
);
// Automatically cleaned up on unload

Event Catalog

Vault Events

EventArgumentsWhen
loadFile tree loaded from adapter
createfile: TAbstractFileFile or folder created
modifyfile: TAbstractFileFile content modified
deletefile: TAbstractFileFile or folder deleted
renamefile: TAbstractFile, oldPath: stringFile or folder renamed/moved
allevent: string, file, contextAny vault event (discriminated)

Workspace Events

EventArgumentsWhen
active-leaf-changeleaf: WorkspaceLeafActive leaf changed
file-changefile: TFile, event: stringExternal file modification detected
layout-changeevent: WorkspaceLayoutChangeEventA committed restorable layout mutation is persisted
layout-will-show-overlayevent: WorkspaceLayoutDropEventA renderer drop target is deciding whether to expose an overlay
layout-will-dropevent: WorkspaceLayoutDropEventA drag/drop layout mutation is about to commit; listeners may cancel
layout-did-dropevent: WorkspaceLayoutDropEventA drag/drop layout mutation committed successfully
layout-readyLayout fully loaded

Current workspace renderer coverage actively emits layout-will-show-overlay, layout-will-drop, layout-did-drop, layout-change, and layout-ready. Workspace also exposes typed layout-drag-start and layout-drag-end helpers for future drag backends, but the current HTML5 renderer path does not yet emit those start/end events consistently.

MetadataCache Events

EventArgumentsWhen
changedfile: TFile, data: string, cache: CachedMetadataFile indexed or re-indexed
deletedfile: TFile, prevCache: CachedMetadataFile removed from cache
loadedCache loaded from storage

Metadata cache events are intentionally low-level and per-file. Search indexing and other vault-wide derived-state owners may listen broadly, but view surfaces are expected to filter these events to the active file or directly affected reference neighborhood whenever they can do so safely.

PluginManager Events

EventArgumentsWhen
plugins-loadedAll plugins loaded from disk
plugin-loadedplugin: PluginSingle plugin loaded
plugin-enabledplugin: PluginPlugin enabled
plugin-disabledplugin: PluginPlugin disabled
plugin-errorerror: ErrorPlugin load/enable error
css-changePlugin CSS modified

CommandManager Events

EventArgumentsWhen
registercommand: CommandCommand registered
unregistercommand: CommandCommand unregistered

Configuration Events

EventArgumentsWhen
updated{key, value, prev}Configuration value changed

Plugin Events

EventArgumentsWhen
enablePlugin enabled
disablePlugin disabled

Editor Events

EventArgumentsWhen
changedata: stringDocument content modified

Event Flow Patterns

File Modification Flow

User edits in CodeMirror
  → Editor.save() (debounced 500ms)
    → vault.modify(file, data)
      → vault emits "modify"
        → watch-vault detects change
          → metadataCache processes file
            → metadataCache emits "changed"
              → searchManager.processChange() updates index
              → metadataTypeManager.processChange() updates types

Plugin Load Flow

PluginManager.loadPlugins()
  → reads /.obsidian/plugins/
    → for each: loadPlugin(path)
      → reads manifest.json
      → dynamicImport(main.js)
      → emits "plugin-loaded"
  → reads community-plugins.json
    → for each enabled: enablePlugin(id)
      → plugin.enable() → plugin.onload()
      → loads styles.css → appends <style>
      → emits "plugin-enabled"
  → emits "plugins-loaded"