Obsidian Plugin & Theme Development
Build plugins and themes for Obsidian using TypeScript, CodeMirror 6, and CSS variables.
Core Principles
- Extend Plugin class - Use
onload() for setup, onunload() for cleanup
- Access app via
this.app - Never use global window.app (debugging only)
- Prefer Vault API - Use
this.app.vault over raw Adapter for file ops
- Wait for layout ready - Use
app.workspace.onLayoutReady() for startup logic
- Register events properly - Use
this.registerEvent() for auto-cleanup
- Mark external CM6 deps - Never bundle
@codemirror/*, use Obsidian's copy
- Use CSS variables - Override theme variables, not hardcoded colors
- Avoid
!important - Let users override with snippets
- Mobile compatibility - Check
Platform.isMobile before Node.js APIs
- Security first - Never use
innerHTML with user input
Quick Reference
// Basic plugin structure
import { Plugin, Notice } from 'obsidian';
export default class MyPlugin extends Plugin {
async onload() {
// Add command
this.addCommand({
id: 'my-command',
name: 'My Command',
callback: () => new Notice('Hello!')
});
// Add ribbon icon
this.addRibbonIcon('dice', 'My Plugin', () => {});
// Register events (auto-cleanup on unload)
this.registerEvent(
this.app.vault.on('modify', (file) => {})
);
// Register CM6 extension
this.registerEditorExtension(myExtension);
}
}
Topics
Plugin Development
Editor Integration
Styling
- Themes & CSS - CSS variables, theme structure, styling patterns
Advanced APIs
Common Patterns
Wait for Vault Ready
async onload() {
this.app.workspace.onLayoutReady(() => {
// Safe to access vault files here
const files = this.app.vault.getMarkdownFiles();
});
}
Process Frontmatter Safely
await this.app.fileManager.processFrontMatter(file, (fm) => {
fm.status = 'done';
});
Register Editor Extension
import { ViewPlugin, DecorationSet } from '@codemirror/view';
const myPlugin = ViewPlugin.fromClass(class {
decorations: DecorationSet;
// ... implementation
}, { decorations: v => v.decorations });
this.registerEditorExtension(myPlugin);
Resources
1---2name: obsidian-43description: Expert knowledge for developing Obsidian plugins and themes using TypeScript, CodeMirror 6, and CSS variables - covers plugin lifecycle, Vault API, Workspace API, editor extensions, and styling patterns4---5
6# Obsidian Plugin & Theme Development
7
8Build plugins and themes for Obsidian using TypeScript, CodeMirror 6, and CSS variables.
9
10## Core Principles
11
12- **Extend Plugin class** - Use `onload()` for setup, `onunload()` for cleanup
13- **Access app via `this.app`** - Never use global `window.app` (debugging only)
14- **Prefer Vault API** - Use `this.app.vault` over raw `Adapter` for file ops
15- **Wait for layout ready** - Use `app.workspace.onLayoutReady()` for startup logic
16- **Register events properly** - Use `this.registerEvent()` for auto-cleanup
17- **Mark external CM6 deps** - Never bundle `@codemirror/*`, use Obsidian's copy
18- **Use CSS variables** - Override theme variables, not hardcoded colors
19- **Avoid `!important`** - Let users override with snippets
20- **Mobile compatibility** - Check `Platform.isMobile` before Node.js APIs
21- **Security first** - Never use `innerHTML` with user input
22
23## Quick Reference
24
25```typescript
26// Basic plugin structure
27import { Plugin, Notice } from 'obsidian';
28
29export default class MyPlugin extends Plugin {
30 async onload() {
31 // Add command
32 this.addCommand({
33 id: 'my-command',
34 name: 'My Command',
35 callback: () => new Notice('Hello!')
36 });
37
38 // Add ribbon icon
39 this.addRibbonIcon('dice', 'My Plugin', () => {});
40
41 // Register events (auto-cleanup on unload)
42 this.registerEvent(
43 this.app.vault.on('modify', (file) => {})
44 );
45
46 // Register CM6 extension
47 this.registerEditorExtension(myExtension);
48 }
49}
50```
51
52## Topics
53
54### Plugin Development
55
56- [Plugin Development](./plugin-development.md) - Lifecycle, API, commands, settings, events
57
58### Editor Integration
59
60- [CodeMirror 6](./codemirror-6.md) - State, view, decorations, extensions
61
62### Styling
63
64- [Themes & CSS](./themes-css.md) - CSS variables, theme structure, styling patterns
65
66### Advanced APIs
67
68- [Bases API](./bases-api.md) - Custom database views (Obsidian 1.10+)
69- [Canvas API](./canvas-api.md) - Visual canvas manipulation
70
71## Common Patterns
72
73### Wait for Vault Ready
74
75```typescript
76async onload() {
77 this.app.workspace.onLayoutReady(() => {
78 // Safe to access vault files here
79 const files = this.app.vault.getMarkdownFiles();
80 });
81}
82```
83
84### Process Frontmatter Safely
85
86```typescript
87await this.app.fileManager.processFrontMatter(file, (fm) => {
88 fm.status = 'done';
89});
90```
91
92### Register Editor Extension
93
94```typescript
95import { ViewPlugin, DecorationSet } from '@codemirror/view';
96
97const myPlugin = ViewPlugin.fromClass(class {
98 decorations: DecorationSet;
99 // ... implementation
100}, { decorations: v => v.decorations });
101
102this.registerEditorExtension(myPlugin);
103```
104
105## Resources
106
107- [Official Docs](https://docs.obsidian.md/Home)
108- [Sample Plugin](https://github.com/obsidianmd/obsidian-sample-plugin)
109- [Sample Theme](https://github.com/obsidianmd/obsidian-sample-theme)
110- [CodeMirror 6 Docs](https://codemirror.net/docs/)