Use this reference for commands, views, settings UI, modals, menus, DOM, styling, accessibility, and framework-mounted interfaces. Confirm APIs and CSS variables against installed declarations, the official reference, and manifest.minAppVersion.
- Choose the UI surface
- Commands and entry points
- Views and workspace
- Settings APIs
- Modals, menus, HTML, and icons
- Obsidian-native styling
- Recommended CSS variable set
- Framework UI lifecycle
- Accessibility and responsive behavior
- Official references
| Need | Preferred surface |
|---|---|
| Conditionally expose an action | Command with checkCallback or editorCheckCallback |
| Show persistent plugin UI | ItemView with a stable view type |
| Collect a short interaction | Modal, SuggestModal, or FuzzySuggestModal |
| Add contextual file/editor actions | Menu through workspace menu events |
| Configure durable values | PluginSettingTab appropriate to the minimum app version |
Avoid a custom view when a command, modal, or menu is sufficient.
- Keep command IDs stable across releases. Obsidian already prefixes them with the plugin ID, so do not repeat that ID.
- Use sentence case for names. Do not include the plugin name when Obsidian already supplies context.
- Avoid default hotkeys; let users choose conflict-free bindings.
- In a
checkCallback, perform no side effects whilecheckingis true. Repeat the same validity check before executing when it is false. - Prefer
editorCallbackfor operations that require an active Markdown editor. - A ribbon icon is optional and user-hideable. Always provide a command or another discoverable route; do not add a separate ribbon-visibility setting.
- Status bar items are desktop-only UI even when the rest of the plugin supports mobile.
- Register a stable view type and construct a fresh
ItemViewin the factory. Do not store the constructed view on the plugin. - Use workspace queries such as
getLeavesOfType()or documented active-view helpers when access is needed. - Render in
contentEland clean owned UI inonClose(). Do not detach leaves in pluginonunload(); preserving leaf placement allows Obsidian to restore views during plugin updates. - Treat
leaf.viewas potentially deferred on supported app versions. CheckDeferredViewbefore casting. PreferrevealLeaf()when the user is about to see it; callloadIfDeferred()only when background loading is truly necessary and compatibility is guarded. - Use
onLayoutReady()for restored-layout work and startup UI that depends on initialized workspace state. - For pop-out windows, derive the owning
windowanddocumentfrom the element (element.win/element.doc), use Obsidian cross-windowinstanceOfhelpers where required, and handle window migration for long-lived views. - Use
activeWindoworactiveDocumentonly when the intended target is whichever window currently has focus.
Choose the implementation from minAppVersion:
| Compatibility target | Implementation |
|---|---|
>= 1.13.0 |
Prefer declarative getSettingDefinitions() |
< 1.13.0, but new declarative behavior is valuable |
Keep display() and add a synchronized declarative definition |
< 1.13.0, no need for declarative features |
Keep the imperative display() implementation |
For declarative settings:
- Keep
getSettingDefinitions()cheap and deterministic. Obsidian calls it repeatedly and during search indexing; do no I/O or network work there. - Prefer built-in control definitions so Obsidian binds and saves top-level settings automatically.
- Use
visibleanddisabledpredicates for conditional behavior. Userenderonly for custom controls, derived values, or side effects. - A
rendercallback must save mutations explicitly and return cleanup for long-lived resources. - Treat
validateas a UI gate, not a data migration. Revalidate and repair stored values during settings loading. - Call
update()after interdependent state or list changes. In dual-support mode, update both implementations together. - Keep page names unique among siblings and use stable row data rather than captured positional indexes for actions.
For all settings UIs:
- Use sentence case. Do not add a top-level heading; add section headings only when multiple sections exist, and do not put “settings” or “options” in headings.
- Use
Setting#setHeading()rather than raw heading elements. - Save on change. Keep one primary control per row so it can stack on mobile.
- Keep descriptions concise and put destructive confirmation in a modal.
- Use
ModalwithSettingfor small structured interactions; useSuggestModalorFuzzySuggestModalfor searchable choices. - Build context menus with
Menuand registered workspace events such as file or editor menus. - Build DOM with
createEl,createDiv,createSpan, and related helpers. Never inject user or vault content withinnerHTML,outerHTML, orinsertAdjacentHTML; clear withempty(). - Use
setIcon()and the bundled Lucide set. Add a custom icon only when necessary and follow Obsidian/Lucide geometry and naming guidance. - Prefer
Noticefor brief, actionable feedback. Keep errors specific without revealing secrets or private note content.
Prefer Obsidian's public UI APIs, documented design tokens, and interaction conventions before introducing plugin-specific equivalents.
- Use documented semantic CSS variables such as
--background-primary,--background-secondary,--background-modifier-border,--background-modifier-hover,--text-normal,--text-muted,--interactive-normal,--interactive-hover, and--interactive-accentinstead of hardcoded colors. - Prefer public Obsidian UI components such as
Setting,ButtonComponent,TextComponent,DropdownComponent,ToggleComponent,Modal,Menu,Notice, andsetIcon()when they provide the required behavior. - Do not depend on undocumented Obsidian DOM structure or internal CSS class names. Use plugin-owned classes for custom structure, state, and styling.
- Start with semantic HTML and Obsidian component APIs. Add custom controls only when native components cannot express the required interaction.
- Put presentation in
styles.cssunder a plugin-owned root class; do not assign hardcoded visual styles from JavaScript. - Keep plugin CSS focused on layout, hierarchy, visualization, and product-specific components rather than replacing Obsidian's entire visual foundation.
- Preserve light and dark theme compatibility and allow community themes to influence the plugin through semantic variables.
- Scope deliberately branded surfaces under a plugin-owned root class. Retain accessible contrast, visible focus, reduced-motion behavior, and usable interaction states in both light and dark themes.
- Derive custom colors, typography, borders, focus states, and interactive states from documented Obsidian variables wherever practical.
- Prefer the curated variable set below and logical CSS properties such as
margin-inline-startso zoom, density, and right-to-left layouts remain coherent. Treat--size-*as a family shorthand only; use a concrete documented variable in CSS. - Test
[dir="rtl"],.mod-rtl, mixed-direction note text, and icons whose direction carries meaning. - Verify any CSS variable against the current official reference and the plugin's declared
minAppVersionbefore relying on it.
Use var(--token) rather than copying default values. This list is a practical plugin-author subset of Obsidian's documented variables; it is not an invitation to redefine theme tokens globally. Popularity alone is not evidence that a token is public: plugin-private names from Calendar, Kanban, or theme snippets are intentionally excluded.
--background-primary
--background-primary-alt
--background-secondary
--background-secondary-alt
--background-modifier-hover
--background-modifier-active-hover
--background-modifier-border
--background-modifier-border-hover
--background-modifier-border-focus
--background-modifier-form-field
--background-modifier-error
--background-modifier-error-hover
--background-modifier-success
--background-modifier-message
--text-normal
--text-muted
--text-faint
--text-accent
--text-accent-hover
--text-on-accent
--text-on-accent-inverted
--text-success
--text-warning
--text-error
--text-selection
--text-highlight-bg
--caret-color
--interactive-normal
--interactive-hover
--interactive-accent
--interactive-accent-hover
Do not add --interactive-accent-hsl to new code; the official reference marks it as deprecated and retained for theme compatibility. Prefer the non-HSL token and modern color functions when a derived color is required.
--color-red
--color-orange
--color-yellow
--color-green
--color-cyan
--color-blue
--color-purple
--color-pink
--accent-h
--accent-s
--accent-l
--color-accent
--color-accent-1
--color-accent-2
Treat these as theme-controlled values for accent-derived decoration, not as plugin settings. Prefer the semantic accent variables over manually combining HSL channels; do not hardcode light/dark accent values or redefine the user's accent.
--font-interface-theme
--font-text-theme
--font-monospace-theme
--font-text-size
--font-ui-smaller
--font-ui-small
--font-ui-medium
--font-ui-large
--line-height-normal
--line-height-tight
--font-weight
--font-smallest
--font-smaller
--font-small
--font-normal
--font-medium
--font-semibold
--font-bold
--font-extrabold
--heading-spacing
--p-spacing
Use fixed --font-ui-* tokens for plugin chrome and relative --font-* tokens for editor-like content. Use the documented weight helpers instead of inventing numeric font variables. Avoid setting a plugin-wide font family or size that defeats the user's Appearance settings.
Do not infer legality from a plugin stylesheet: some plugins reference ambient names such as --font-monospace, but the current official reference documents --font-monospace-theme instead. Prefer the documented token unless the target Obsidian version explicitly guarantees another variable.
--border-width
--radius-s
--radius-m
--radius-l
--radius-xl
--size-4-1
--size-4-2
--size-4-3
--size-4-4
--size-4-5
--size-4-6
--size-4-8
--size-4-9
--size-4-12
--size-4-16
--size-4-18
Use the 4-pixel grid for normal layout. The documented --size-2-1, --size-2-2, and --size-2-3 tokens are available for fine adjustments, but should be used sparingly.
--layer-cover
--layer-sidedock
--layer-status-bar
--layer-popover
--layer-slides
--layer-modal
--layer-notice
--layer-menu
--layer-tooltip
--layer-dragged-item
Use a documented layer only when the surface has the corresponding semantic role. Do not invent arbitrary z-index values or override Obsidian's global layer scale.
--icon-size
--icon-stroke
--icon-color
--icon-color-hover
--icon-color-active
--icon-color-focused
--icon-opacity
--icon-opacity-hover
--icon-opacity-active
--clickable-icon-radius
--icon-xs
--icon-s
--icon-m
--icon-l
--icon-xl
Prefer setIcon() and Lucide icons; use these tokens when a plugin-owned icon wrapper needs to align with Obsidian's icon sizing, stroke, or interaction states.
Use component tokens only for the matching native surface; do not use them as general-purpose replacements for semantic colors or spacing.
--button-radius
--input-height
--input-radius
--input-font-weight
--input-border-width
--toggle-border-width
--toggle-width
--toggle-radius
--modal-background
--modal-border-width
--modal-border-color
--modal-radius
--nav-item-size
--nav-item-color
--nav-item-color-hover
--nav-item-color-selected
--nav-item-background-hover
--nav-item-background-selected
--nav-item-padding
The component pages define additional specialized tokens. Add one here only when a plugin repeatedly styles that native component and the token is documented for the target minAppVersion.
Use these when a plugin renders a table or intentionally matches Obsidian's editor table surface. Dataview's public stylesheet, for example, uses --table-row-background-hover together with Obsidian's background, text-selection, and navigation tokens.
--table-background
--table-border-width
--table-border-color
--table-header-background
--table-header-background-hover
--table-header-border-width
--table-header-border-color
--table-header-color
--table-line-height
--table-text-size
--table-text-color
--table-row-background-hover
--table-row-alt-background
--table-row-alt-background-hover
--table-selection
--table-selection-border-color
--table-selection-border-width
--table-selection-border-radius
Do not assume these tokens apply to arbitrary cards or lists; scope them to a plugin-owned table root or a matching editor-rendered surface.
These tokens are useful for task views, checklist renderers, and controls that intentionally match Obsidian's native checkbox appearance.
--checkbox-size
--checkbox-radius
--checkbox-marker-color
--checkbox-color
--checkbox-color-hover
--checkbox-border-color
--checkbox-border-color-hover
--checklist-done-decoration
--checklist-done-color
--divider-color
--divider-color-hover
--divider-width
--divider-width-hover
--divider-vertical-height
Use divider tokens for separators and resize affordances; preserve the semantic direction and interactive state rather than substituting a hardcoded border color.
- Mount React or Svelte only into an element owned by the plugin or view.
- Unmount React roots and Svelte components in the matching
onClose()or component cleanup. - Pass
Appand services as dependencies or context; do not use globalapp. - Keep Obsidian CSS variables and interaction conventions inside framework components.
- Give icon-only controls an accessible label and preserve visible focus.
- Keep native keyboard behavior and tab order; do not make a clickable
divwhen a button or link is appropriate. - Announce meaningful asynchronous status and errors without creating noisy repeated notices.
- Respect
prefers-reduced-motionand do not encode state by color alone. - Test long localized text, zoom, empty/loading/error/disabled states, narrow panes, pop-out windows, touch targets, and software-keyboard overlap.
- Verify light and dark themes plus at least one community theme when custom CSS is substantial.
- User interface
- Settings
- Views
- HTML elements
- CSS variables
- CSS variable colors
- CSS variable typography
- CSS variable spacing
- CSS variable borders
- CSS variable radiuses
- CSS variable icons
- CSS variable layers
- CSS variable button
- CSS variable checkbox
- CSS variable text input
- CSS variable toggle
- CSS variable modal
- CSS variable navigation
- CSS variable tables
- CSS variable dividers
- Right-to-left text
- Use React
- Use Svelte