Skip to main content

Overview

The Plugin class is the abstract base class that all Obsidian plugins must extend. It provides the foundation for plugin lifecycle management, UI integration, and access to the Obsidian API through the app property. The Plugin class extends Component, inheriting all component lifecycle methods. Available since: v0.9.7

Constructor

constructor(app: App, manifest: PluginManifest)
Creates a new plugin instance. This is typically called automatically by Obsidian when loading your plugin.
app
App
required
The main App instance providing access to the Obsidian API.
manifest
PluginManifest
required
The plugin manifest containing metadata like id, name, version, etc.

Properties

app
App
Reference to the main App instance, providing access to all Obsidian APIs.Since: v0.9.7
manifest
PluginManifest
The plugin’s manifest containing metadata such as id, name, version, author, and description.Since: v0.9.7

Lifecycle Methods

onload()

Called when the plugin is loaded. Override this method to initialize your plugin, register commands, add ribbon icons, and set up event handlers. Returns: Promise<void> | void Since: v0.9.7
export default class MyPlugin extends Plugin {
  async onload() {
    console.log('Loading my plugin');
    
    // Load settings
    await this.loadData();
    
    // Register commands
    this.addCommand({
      id: 'my-command',
      name: 'My Command',
      callback: () => {
        console.log('Command executed');
      }
    });
  }
}

onUserEnable()

Called when the user explicitly enables the plugin for the first time. Use this for initial setup that requires user interaction, such as opening a custom view or showing a welcome message. Returns: void Since: v1.7.2
onUserEnable() {
  // Show welcome notice on first enable
  new Notice('Welcome to My Plugin! Check the settings to configure.');
}

onExternalSettingsChange()

Called when the data.json file is modified externally (e.g., by a sync service). Implement this to reload settings when they change outside of Obsidian. Returns: any Since: v1.5.7
async onExternalSettingsChange() {
  // Reload settings from disk
  this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
  console.log('Settings reloaded from external change');
}

UI Methods

addRibbonIcon()

Adds an icon to the left ribbon bar.
icon
IconName
required
The icon name to display. See Icon documentation for available icons.
title
string
required
The tooltip text shown when hovering over the icon.
callback
(evt: MouseEvent) => any
required
The callback function executed when the icon is clicked.
Returns: HTMLElement - The created ribbon icon element. Since: v0.9.7
this.addRibbonIcon('dice', 'Open Random Note', (evt: MouseEvent) => {
  console.log('Ribbon icon clicked!');
  // Open a random note
});

addStatusBarItem()

Adds a status bar item to the bottom of the app. Not available on mobile devices. Returns: HTMLElement - The status bar element to populate with content. Since: v0.9.7
const statusBarItem = this.addStatusBarItem();
statusBarItem.setText('Word count: 1000');

Command Registration

addCommand()

Registers a command globally. Commands appear in the command palette and can be assigned hotkeys. The command id and name are automatically prefixed with your plugin’s id and name.
command
Command
required
The command configuration object containing id, name, callback, and optional properties.
Returns: Command - The registered command object. Since: v0.9.7
this.addCommand({
  id: 'open-sample-modal',
  name: 'Open Sample Modal',
  callback: () => {
    new SampleModal(this.app).open();
  }
});

// Command with editor check
this.addCommand({
  id: 'insert-text',
  name: 'Insert Text',
  editorCallback: (editor: Editor, view: MarkdownView) => {
    editor.replaceSelection('Hello from plugin!');
  }
});

removeCommand()

Manually removes a command. Only needed if your plugin registers commands dynamically.
commandId
string
required
The ID of the command to remove (without the plugin prefix).
Returns: void Since: v1.7.2
this.removeCommand('temporary-command');

Settings

addSettingTab()

Registers a settings tab that appears in the settings panel.
settingTab
PluginSettingTab
required
The settings tab instance to register.
Returns: void Since: v0.9.7
this.addSettingTab(new MyPluginSettingTab(this.app, this));

loadData()

Loads settings data from data.json in the plugin folder. Returns: Promise<any> - The parsed data from the file, or null if the file doesn’t exist. Since: v0.9.7
async onload() {
  this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
}

saveData()

Writes settings data to data.json in the plugin folder.
data
any
required
The data object to serialize and save. Must be JSON-serializable.
Returns: Promise<void> Since: v0.9.7
async saveSettings() {
  await this.saveData(this.settings);
}

View Registration

registerView()

Registers a custom view type with the workspace.
type
string
required
A unique identifier for this view type.
viewCreator
ViewCreator
required
A factory function that creates view instances: (leaf: WorkspaceLeaf) => View
Returns: void Since: v0.9.7
this.registerView(
  'my-custom-view',
  (leaf) => new MyCustomView(leaf)
);

registerExtensions()

Registers file extensions to be handled by a specific view type.
extensions
string[]
required
Array of file extensions (without the dot).
viewType
string
required
The view type that should handle these extensions.
Returns: void Since: v0.9.7
this.registerExtensions(['csv', 'tsv'], 'spreadsheet-view');

Editor Extensions

registerEditorExtension()

Registers a CodeMirror 6 extension. To dynamically reconfigure extensions, pass an array that can be modified, then call Workspace.updateOptions() to apply changes.
extension
Extension
required
A CodeMirror 6 Extension or array of Extensions.
Returns: void Since: v0.12.8
import { EditorView } from '@codemirror/view';

const theme = EditorView.theme({
  '.cm-content': { fontSize: '16px' }
});

this.registerEditorExtension(theme);

registerEditorSuggest()

Registers an EditorSuggest that provides live autocomplete suggestions while typing.
editorSuggest
EditorSuggest<any>
required
The editor suggest instance to register.
Returns: void Since: v0.12.7
this.registerEditorSuggest(new MyCustomSuggest(this.app));

Markdown Processing

registerMarkdownPostProcessor()

Registers a post processor to transform rendered markdown in reading mode.
postProcessor
MarkdownPostProcessor
required
The post processor function: (el: HTMLElement, ctx: MarkdownPostProcessorContext) => Promise<any> | void
sortOrder
number
Optional sort order to control when this processor runs relative to others.
Returns: MarkdownPostProcessor - The registered post processor. Since: v0.9.7
this.registerMarkdownPostProcessor((element, context) => {
  // Find all code blocks and add copy buttons
  element.findAll('code').forEach(codeEl => {
    // Add copy functionality
  });
});

registerMarkdownCodeBlockProcessor()

Registers a handler for fenced code blocks with a specific language. The <pre><code> wrapper is automatically removed, and a <div> is provided for custom rendering.
language
string
required
The language identifier for the code block (e.g., ‘mermaid’, ‘dataview’).
handler
(source: string, el: HTMLElement, ctx: MarkdownPostProcessorContext) => Promise<any> | void
required
Function that receives the code block source, container element, and context.
sortOrder
number
Optional sort order for execution priority.
Returns: MarkdownPostProcessor - The registered processor. Since: v0.9.7
this.registerMarkdownCodeBlockProcessor('my-lang', (source, el, ctx) => {
  const div = el.createDiv();
  div.setText(`Processed: ${source}`);
});

Protocol Handlers

registerObsidianProtocolHandler()

Registers a handler for obsidian:// URLs.
action
string
required
The action identifier (e.g., ‘open’ for obsidian://open).
handler
ObsidianProtocolHandler
required
Callback that receives the parsed URL parameters: (params: ObsidianProtocolData) => any
Returns: void Since: v0.11.0
this.registerObsidianProtocolHandler('my-action', (params) => {
  // Handle obsidian://my-action?key=value
  console.log('Action called with:', params);
});

CLI Integration

registerCliHandler()

Registers a CLI command handler. Command IDs must be globally unique.
command
string
required
The command ID (use format <plugin-id> or <plugin-id>:<action>).
description
string
required
Description shown in help and autocomplete.
flags
CliFlags | null
required
Command line flags configuration, or null if no flags needed.
handler
CliHandler
required
The handler function to process CLI invocations.
Returns: void Since: v1.12.2
this.registerCliHandler(
  'my-plugin:export',
  'Export vault data',
  { format: { type: 'string', description: 'Export format' } },
  async (args) => {
    console.log(`Exporting in ${args.format} format`);
  }
);

Complete Example

import { Plugin, PluginSettingTab, Setting, Notice } from 'obsidian';

interface MyPluginSettings {
  apiKey: string;
  enabled: boolean;
}

const DEFAULT_SETTINGS: MyPluginSettings = {
  apiKey: '',
  enabled: true
}

export default class MyPlugin extends Plugin {
  settings: MyPluginSettings;

  async onload() {
    // Load settings
    await this.loadSettings();

    // Add ribbon icon
    this.addRibbonIcon('dice', 'My Plugin', (evt: MouseEvent) => {
      new Notice('Ribbon icon clicked!');
    });

    // Add status bar
    const statusBarItem = this.addStatusBarItem();
    statusBarItem.setText('Status: Active');

    // Add command
    this.addCommand({
      id: 'process-file',
      name: 'Process Current File',
      callback: async () => {
        const file = this.app.workspace.getActiveFile();
        if (file) {
          const content = await this.app.vault.read(file);
          new Notice(`File has ${content.length} characters`);
        }
      }
    });

    // Register markdown processor
    this.registerMarkdownCodeBlockProcessor('my-lang', (source, el, ctx) => {
      el.createDiv({ text: `Custom rendering: ${source}` });
    });

    // Add settings tab
    this.addSettingTab(new MyPluginSettingTab(this.app, this));
  }

  async loadSettings() {
    this.settings = Object.assign({}, DEFAULT_SETTINGS, await this.loadData());
  }

  async saveSettings() {
    await this.saveData(this.settings);
  }
}

class MyPluginSettingTab extends PluginSettingTab {
  plugin: MyPlugin;

  constructor(app: App, plugin: MyPlugin) {
    super(app, plugin);
    this.plugin = plugin;
  }

  display(): void {
    const {containerEl} = this;
    containerEl.empty();

    new Setting(containerEl)
      .setName('API Key')
      .setDesc('Enter your API key')
      .addText(text => text
        .setPlaceholder('Enter key')
        .setValue(this.plugin.settings.apiKey)
        .onChange(async (value) => {
          this.plugin.settings.apiKey = value;
          await this.plugin.saveSettings();
        }));
  }
}
  • App - Main application interface
  • Component - Base class for lifecycle management (parent class of Plugin)
  • PluginManifest - Plugin metadata interface
  • Command - Command registration interface
  • ViewCreator - Type alias for view factory functions: (leaf: WorkspaceLeaf) => View
  • IconName - Type alias for icon identifiers (string)

Build docs developers (and LLMs) love