Skip to content

CSS and JavaScript

Anup Chavan edited this page Jun 21, 2026 · 1 revision

CSS and JavaScript

Each Custom View can have scoped CSS and optional JavaScript. Keep HTML declarative, CSS responsible for layout, and JavaScript only for behavior that cannot be expressed in the template itself.

CSS field

The CSS field is the best place for view styles. Use normal CSS and Obsidian CSS variables.

.album-view {
  color: var(--text-normal);
  background: var(--background-primary);
}

.album-view a {
  color: var(--link-color);
}

Prefer Obsidian variables where possible:

Variable Common use
--background-primary Main background.
--background-secondary Secondary panels.
--text-normal Body text.
--text-muted Supporting text.
--text-faint Dividers and faint labels.
--interactive-accent Accent color.
--background-modifier-border Borders.

JavaScript field

The JavaScript field runs after the template is rendered, if Allow JavaScript execution is enabled.

Inside view JavaScript, this is the rendered custom-view container.

const container = this;
const button = container.querySelector("button");

button?.addEventListener("click", () => {
  container.classList.toggle("is-expanded");
});

Always scope DOM queries to this, not document, unless you intentionally need something global.

Inline scripts

Inline <script> tags in templates can also run, but the JavaScript field is easier to maintain. Prefer the JavaScript field for larger behavior.

Security and privacy

JavaScript can call network APIs, inspect rendered note data, and mutate the page. Only enable and paste scripts you trust.

For API keys:

  • Prefer placeholders in shared templates.
  • Do not publish personal keys in screenshots, gists, issues, or wiki pages.
  • Keep third-party requests clear to the user.

Palette extraction and images

The Movies and Albums examples sample colors from cover/backdrop images. Canvas sampling can fail if the image is cross-origin and does not allow it. Always provide a fallback palette.

Pattern:

const img = container.querySelector(".album-cover");

function applyFallbackPalette() {
  container.style.setProperty("--background-primary", "#100f0f");
}

if (img?.complete && img.naturalWidth > 0) {
  // sample image here
} else {
  img?.addEventListener("load", () => {
    // sample image here
  });
  img?.addEventListener("error", applyFallbackPalette);
}

Performance habits

  • Keep JavaScript idempotent; it may run again when switching files.
  • Avoid repeated global document.querySelectorAll scans.
  • Avoid long synchronous loops over the whole vault.
  • Use Bases for related-file querying instead of custom JavaScript vault scans.
  • If you fetch remote data, show a small fallback state and cache where appropriate.

Wiki pages

Clone this wiki locally