| name | obsidian |
| version | 1.1.0 |
| description | Comprehensive guidelines for Obsidian.md plugin development including all 27 ESLint rules, TypeScript best practices, memory management, API usage (requestUrl vs fetch), UI/UX standards, and submission requirements. Use when working with Obsidian plugins, main.ts files, manifest.json, Plugin class, MarkdownView, TFile, vault operations, or any Obsidian API development. |
Obsidian Plugin Development Guidelines
You are assisting with Obsidian plugin development. Follow these comprehensive guidelines derived from the official Obsidian ESLint plugin rules, submission requirements, and best practices.
Core Principles
- Memory Safety: Prevent memory leaks through proper resource management
- Type Safety: Use proper type narrowing and avoid unsafe casts
- API Best Practices: Follow Obsidian's recommended patterns
- User Experience: Maintain consistency in UI/UX across plugins
- Platform Compatibility: Ensure cross-platform support (including iOS)
- Accessibility: Make all features keyboard and screen reader accessible
Quick Reference
Top 27 Most Critical Rules
Submission & Naming:
- Plugin ID: no "obsidian", can't end with "plugin" - Validation bot enforced
- Plugin name: no "Obsidian", can't end with "Plugin" - Validation bot enforced
- Plugin name: can't start with "Obsi" or end with "dian" - Validation bot enforced
- Description: no "Obsidian", "This plugin", etc. - Validation bot enforced
- Description must end with
.?!) punctuation - Validation bot enforced
Memory & Lifecycle: 6. Use registerEvent() for automatic cleanup - Prevents memory leaks 7. Don't store view references in plugin - Causes memory leaks
Type Safety: 8. Use instanceof instead of type casting - Type safety for TFile/TFolder
UI/UX: 9. Use sentence case for all UI text - "Advanced settings" not "Advanced Settings" 10. No "command" in command names/IDs - Redundant 11. No plugin ID in command IDs - Obsidian auto-namespaces 12. No default hotkeys - Avoid conflicts 13. Use .setHeading() for settings headings - Not manual HTML
API Best Practices: 14. Use Editor API for active file edits - Preserves cursor position 15. Use Vault.process() for background file mods - Prevents conflicts 16. Use normalizePath() for user paths - Cross-platform compatibility 17. Use Platform API for OS detection - Not navigator 18. Use requestUrl() instead of fetch() - Bypasses CORS restrictions 19. No console.log in onload/onunload in production - Pollutes console
Styling: 20. Use Obsidian CSS variables - Respects user themes 21. Scope CSS to plugin containers - Prevents style conflicts
Accessibility (MANDATORY): 22. Make all interactive elements keyboard accessible - Accessibility required 23. Provide ARIA labels for icon buttons - Accessibility required 24. Define clear focus indicators - Use :focus-visible
Security & Compatibility: 25. Don't use innerHTML/outerHTML - Security risk (XSS) 26. Avoid regex lookbehind - iOS < 16.4 incompatibility
Code Quality: 27. Remove all sample/template code - MyPlugin, SampleModal, etc.
Review Bot (CodeMirror plugins): 28. Avoid | null unions with @codemirror/* types - Bot can't resolve them; use optional properties (?) instead 29. void unmount() for Svelte 5 - unmount() returns Promise, must be handled 30. eslint-plugin-obsidian requires ESLint 8 - Incompatible with ESLint 9+/10+
Detailed Guidelines
For comprehensive information on specific topics, see the reference files:
- Using
registerEvent(), addCommand(), registerDomEvent(), registerInterval()
- Avoiding view references in plugin
- Not using plugin as component
- Proper leaf cleanup
- Using
instanceof instead of type casting
- Avoiding
any type
- Using
const and let over var
- Sentence case enforcement
- Command naming conventions
- Settings and configuration best practices
- View access patterns
- Editor vs Vault API
- Atomic file operations
- File management
- Path handling
- Avoiding inline styles
- Using Obsidian CSS variables
- Scoping plugin styles
- Theme support
- Spacing and layout
- Keyboard navigation (MANDATORY)
- ARIA labels and roles (MANDATORY)
- Tooltips and accessibility
- Focus management (MANDATORY)
- Focus visible styles (MANDATORY)
- Screen reader support (MANDATORY)
- Mobile and touch accessibility (MANDATORY)
- Accessibility checklist
- Removing sample code
- Security best practices
- Platform compatibility
- API usage best practices
- Async/await patterns
- DOM helpers
- Repository structure
- ObsidianReviewBot automated scan (CodeMirror type workarounds,
/skip process)
eslint-plugin-obsidian local testing limitations
- Submission process
- Semantic versioning
- Testing checklist
Essential Do's and Don'ts
Do's ✅
Memory & Lifecycle:
- Use
registerEvent(), addCommand(), registerDomEvent(), registerInterval()
- Return views/components directly (don't store unnecessarily)
Type Safety:
- Use
instanceof for type checking (not type casting)
- Use specific types or
unknown instead of any
- Use
const and let (not var)
API Usage:
- Use
this.app (not global app)
- Use Editor API for active file edits
- Use
Vault.process() for background file modifications
- Use
FileManager.processFrontMatter() for YAML
- Use
fileManager.trashFile() for deletions
- Use
normalizePath() for user-defined paths
- Use
Platform API for OS detection
- Use
AbstractInputSuggest for autocomplete
- Use direct file lookups (not vault iteration)
- Use
requestUrl() instead of fetch() for network requests
UI/UX:
- Use sentence case for all UI text
- Use
.setHeading() for settings headings
- Use Obsidian DOM helpers (
createDiv(), createSpan(), createEl())
- Use
window.setTimeout/setInterval with number type
Styling:
- Move all styles to CSS
- Use Obsidian CSS variables for all styling
- Scope CSS to plugin containers
- Support both light and dark themes via CSS variables
- Follow Obsidian's 4px spacing grid
Accessibility (MANDATORY):
- Make all interactive elements keyboard accessible
- Provide ARIA labels for icon buttons
- Define clear focus indicators using
:focus-visible
- Use
data-tooltip-position for tooltips
- Ensure minimum touch target size (44×44px)
- Manage focus properly in modals
- Test with keyboard navigation
Code Quality:
- Use async/await (not Promise chains)
- Remove all sample/template code
- Test on mobile (if not desktop-only)
- Follow semantic versioning
- Minimize console logging (no console.log in onload/onunload in production)
Don'ts ❌
Memory & Lifecycle:
- Don't store view references in plugin properties
- Don't pass plugin as component to MarkdownRenderer
- Don't detach leaves in
onunload()
Type Safety:
- Don't cast to TFile/TFolder (use
instanceof)
- Don't use
any type
- Don't use
var
API Usage:
- Don't use global
app object
- Don't use
Vault.modify() for active file edits
- Don't hardcode
.obsidian path (use vault.configDir)
- Don't use
navigator.platform/userAgent (use Platform API)
- Don't iterate vault when direct lookup exists
- Don't use
fetch() (use requestUrl() instead)
UI/UX:
- Don't use Title Case in UI (use sentence case)
- Don't include "command" in command names/IDs
- Don't duplicate plugin ID in command IDs
- Don't set default hotkeys
- Don't create manual HTML headings (use
.setHeading())
- Don't use "General", "settings", or plugin name in settings headings
Styling:
- Don't assign styles via JavaScript
- Don't hardcode colors, sizes, or spacing (use CSS variables)
- Don't use broad CSS selectors (scope to plugin)
- Don't manually switch themes (CSS variables adapt automatically)
- Don't create
<link> or <style> elements (use styles.css file)
Security & Compatibility:
- Don't use
innerHTML/outerHTML (XSS risk)
- Don't use regex lookbehind (iOS < 16.4 incompatibility)
Accessibility:
- Don't create inaccessible interactive elements
- Don't use icon buttons without ARIA labels
- Don't remove focus indicators without alternatives
- Don't make touch targets smaller than 44×44px
Code Quality:
- Don't use Promise chains (use async/await)
- Don't use
document.createElement (use Obsidian helpers)
- Don't keep sample class names (MyPlugin, SampleModal, etc.)
- Don't use console.log in onload/onunload (pollutes console in production)
When Reviewing/Writing Code
Use this checklist for code review and implementation:
- Memory management: Are components and views properly managed?
- Type safety: Using
instanceof instead of casts?
- UI text: Is everything in sentence case?
- Command naming: No redundant words?
- File operations: Using preferred APIs?
- Mobile compatibility: No iOS-incompatible features?
- Sample code: Removed all boilerplate?
- Manifest: Correct version, valid structure?
- Accessibility: Keyboard navigation, ARIA labels, focus indicators?
- Testing: Can you use the plugin without a mouse?
- Touch targets: Are all interactive elements at least 44×44px?
- Focus styles: Using
:focus-visible and proper CSS variables?
Common Patterns
Proper Command Registration
this.addCommand({
id: 'insert-timestamp',
name: 'Insert timestamp',
editorCallback: (editor: Editor, view: MarkdownView) => {
editor.replaceSelection(new Date().toISOString());
},
});
Safe Type Narrowing
const file = this.app.vault.getAbstractFileByPath(path);
if (file instanceof TFile) {
await this.app.vault.read(file);
}
Keyboard Accessible Button
const button = containerEl.createEl('button', {
attr: {
'aria-label': 'Open settings',
'data-tooltip-position': 'top',
},
});
button.setText('⚙️');
button.addEventListener('click', () => {
performAction();
});
Themed CSS
.my-plugin-modal {
background: var(--modal-background);
color: var(--text-normal);
padding: var(--size-4-4);
border-radius: var(--radius-m);
font-size: var(--font-ui-medium);
}
.my-plugin-button:focus-visible {
outline: 2px solid var(--interactive-accent);
outline-offset: 2px;
}
Additional Resources
Important Notes
- These guidelines are based on
eslint-plugin-obsidianmd which is under active development
- Rules marked as auto-fixable can be automatically corrected with ESLint's
--fix flag
- Accessibility is NOT optional - all interactive elements must be keyboard accessible
- Always test on mobile devices if your plugin is not desktop-only
When helping with Obsidian plugin development, proactively apply these rules and suggest improvements based on these guidelines. Refer to the detailed reference files for comprehensive information on specific topics.