All skills
gapmiss avatar

/obsidian

@ff97cb0

Comprehensive guidelines for Obsidian.md plugin development including ESLint rules from eslint-plugin-obsidianmd v0.4.2, TypeScript best practices, memory management, API usage (requestUrl vs fetch), UI/UX standards, popout window compatibility, community.obsidian.md submission process, and Scorecard optimization. Use when working with Obsidian plugins, main.ts files, manifest.json, Plugin class, MarkdownView, TFile, vault operations, or any Obsidian API development.

Use this Skill: https://skilld.dev/gh/gapmiss/obsidian-plugin-skill/obsidian

This session only. Nothing lands on disk.

referenceaccessibility.md

≈2k tokens on demand. Your agent reads this file only when SKILL.md points to it.

Accessibility (A11y)

Accessibility is MANDATORY for Obsidian plugins. All users, regardless of ability, must be able to use your plugin.

Table of Contents


Keyboard Navigation

Keyboard Navigation

Rule: Accessibility best practice - MANDATORY

All interactive elements must be keyboard accessible. Users should be able to navigate and interact with your plugin using only the keyboard.

✅ CORRECT:

// Make custom interactive elements keyboard accessible
element.setAttribute('tabindex', '0');
element.setAttribute('role', 'button');
element.setAttribute('aria-label', 'Click to change active profile');

element.addEventListener('keydown', (e) => {
  if (e.key === 'Enter' || e.key === ' ') {
    e.preventDefault();
    performAction();
  }
});

Key Requirements:

  • Add tabindex="0" to make elements keyboard focusable
  • Support both Enter and Space keys for button-like elements
  • Use arrow keys for navigation within lists/menus
  • Call e.preventDefault() to prevent default scroll behavior on Space

ARIA Labels and Roles

ARIA Labels and Roles

Rule: Accessibility best practice - MANDATORY

Provide proper ARIA labels and roles for all interactive elements, especially icons and buttons without visible text.

❌ INCORRECT:

// Icon button with no accessible label
const button = containerEl.createEl('button');
button.innerHTML = '⚙️';

✅ CORRECT:

// Icon button with proper ARIA label
const button = containerEl.createEl('button', {
  attr: {
    'aria-label': 'Open settings',
    'type': 'button'
  }
});
button.setText('⚙️');

Common ARIA attributes:

  • aria-label: Accessible name for elements without visible text
  • aria-description: Additional context beyond the label
  • role: Semantic role (button, dialog, menu, listbox, etc.)
  • aria-expanded: For collapsible/expandable elements
  • aria-selected: For selectable items in lists
  • aria-disabled: For disabled but visible elements

Tooltips and Accessibility

Tooltips and Accessibility

Rule: Obsidian API best practice

Use Obsidian's built-in tooltip system with proper positioning and accessibility attributes.

✅ CORRECT:

const button = containerEl.createEl('button', {
  attr: {
    'aria-label': 'Open settings',
    'data-tooltip-position': 'top'  // Position tooltip above element
  }
});
setTooltip(button, 'Open settings');

// Alternative using setAttr
button.setAttr('aria-label', 'Refresh view');
button.setAttr('data-tooltip-position', 'bottom');

Tooltip Position Options:

  • top: Above the element (default for many cases)
  • bottom: Below the element
  • left: To the left of the element
  • right: To the right of the element

Important: Always provide aria-label in addition to tooltips, as tooltips may not be accessible to screen readers.


Focus Management

Focus Management

Rule: Accessibility best practice - MANDATORY

Manage focus appropriately when opening modals, menus, or changing context.

✅ CORRECT:

export class MyModal extends Modal {
  onOpen() {
    const { contentEl } = this;

    // Create focusable content
    const input = contentEl.createEl('input', {
      attr: { 'aria-label': 'Enter value' }
    });

    // Focus the first interactive element
    input.focus();
  }

  onClose() {
    const { contentEl } = this;
    contentEl.empty();
    // Focus returns to trigger element automatically
  }
}

Focus Best Practices:

  • Focus the first interactive element when opening modals
  • Trap focus within modals (prevent Tab from leaving modal)
  • Return focus to the trigger element when closing modals
  • Define focus styles in CSS using :focus-visible

Focus Visible Styles

Focus Visible Styles

Rule: Accessibility best practice - MANDATORY

Define clear focus indicators using CSS :focus-visible pseudo-class.

✅ CORRECT:

/* Option 1: Using outline (standard approach) */
.my-plugin-button:focus-visible {
  outline: 2px solid var(--interactive-accent);
  outline-offset: 2px;
}

/* Option 2: Using Obsidian's focus box-shadow pattern */
.my-plugin-input:focus,
.my-plugin-input:focus-visible {
  box-shadow: 0 0 0 3px var(--background-modifier-border-focus);
  border-radius: var(--input-radius);
}

/* Option 3: Alternative focus indicator */
.my-plugin-list-item:focus-visible {
  background: var(--background-modifier-hover);
  box-shadow: inset 0 0 0 2px var(--interactive-accent);
}

Focus Indicator Guidelines:

  • Always provide visible focus indicators
  • Use :focus-visible (not :focus) to show only for keyboard navigation
  • Use Obsidian's CSS variables:
    • --background-modifier-border-focus for focus borders/shadows
    • --interactive-accent for accent color
    • --input-radius for input border radius
  • The box-shadow pattern is preferred for inputs and form elements
  • Don't remove outlines without providing alternative indicators

Screen Reader Support

Screen Reader Support

Rule: Accessibility best practice - MANDATORY

Ensure your plugin works well with screen readers.

✅ CORRECT:

// Announce dynamic changes to screen readers
const statusEl = containerEl.createEl('div', {
  attr: {
    'role': 'status',
    'aria-live': 'polite',
    'aria-atomic': 'true'
  }
});
statusEl.setText('File saved successfully');

// Use semantic HTML when possible
const list = containerEl.createEl('ul', {
  attr: { 'role': 'list' }
});

const item = list.createEl('li', {
  attr: { 'role': 'listitem' }
});

Screen Reader Considerations:

  • Use aria-live regions for dynamic content updates
  • Provide meaningful aria-label for icons and images
  • Use semantic HTML roles when available
  • Test with actual screen readers (NVDA, JAWS, VoiceOver)

Mobile and Touch Accessibility

Mobile and Touch Accessibility

Rule: Platform compatibility - MANDATORY

Ensure touch targets are appropriately sized and spaced for mobile users.

✅ CORRECT:

.my-plugin-button {
  /* Minimum touch target size: 44x44px */
  min-width: 44px;
  min-height: 44px;

  /* Adequate spacing between touch targets */
  margin: var(--size-4-2);

  /* Padding for visual size vs. touch target */
  padding: var(--size-4-2) var(--size-4-4);
}

Touch Target Guidelines:

  • Minimum touch target size: 44×44 pixels (iOS), 48×48 pixels (Android)
  • Provide adequate spacing between interactive elements
  • Support both click and touch events
  • Test on actual mobile devices (iOS)

Accessibility Checklist

IMPORTANT: Accessibility is NOT optional. When implementing UI elements, ensure:

  • All interactive elements are keyboard accessible (Enter/Space support)
  • Tab order is logical and intuitive
  • Focus indicators are visible and clear (:focus-visible)
  • ARIA labels provided for icon-only buttons
  • ARIA roles defined for custom controls
  • Focus managed properly in modals/dialogs
  • Dynamic content changes announced to screen readers (aria-live)
  • Touch targets meet minimum size requirements (44×44px minimum)
  • Color contrast meets WCAG AA standards (use Obsidian CSS variables)
  • No information conveyed by color alone
  • Tooltips positioned appropriately (data-tooltip-position)
  • Tested with keyboard navigation (Tab, Enter, Space, Arrow keys)
  • Tested with screen reader (if possible)

Source: SKILL.md on GitHub

No alerts4d5 checks · Risk SAFE
  • Gen Agent Trust Hub5d

    The skill is a comprehensive, high-quality documentation resource for Obsidian.md plugin development. It provides correct security guidance (such as XSS prevention), memory management practices, and accessibility standards. No malicious code, data exfiltration, or obfuscation was detected.

  • Socket4d

    No alerts

  • Snyk5d

    Risk: LOW · No issues

  • Runlayer7mo

    9 files scanned · No issues

  • ZeroLeaks5mo

    Score: 93/100 · 2 sections analyzed

Signed by skilld at ff97cb0. This ties the file your Agent reads to that commit on GitHub. It does not review the instructions.

Last checked against GitHub last week.

Activeupdated last week
metadata
{
  "version": "1.11.1"
}

README badge

README badge for gapmiss/obsidian-plugin-skill