Robin Tan576 downloadsRenders HTML documents natively in Obsidian workspace tabs with local CSS, image, and script asset resolution, CSP security, and link interception.
Render .html and .htm files in Obsidian tabs or inside Markdown notes, with local styles, images, fonts, scripts and live reload.
The command palette provides Reload HTML preview, Toggle HTML source / preview, Find in HTML preview, and Print HTML / save PDF while an HTML tab is active.
Add an html-viewer fenced block containing a vault file path:
```html-viewer
../lessons/example.html
```
Paths resolve relative to the Markdown note. Prefix a path with / to start at the vault root. The embed uses the same controls, isolation, diagnostics and live reload as a workspace tab. It works wherever Obsidian renders Markdown code blocks, including Reading view and rendered Live Preview blocks. Its bottom edge can be dragged to resize it.
Relative paths, percent-encoded filenames, image srcset, CSS url() and recursive local CSS imports are resolved through the vault API. Stylesheets are inlined with their media, layer and supports conditions preserved. Binary assets and local scripts are embedded as data URLs so the preview can run with an opaque origin.
The iframe uses sandbox="allow-scripts allow-modals". It never receives same-origin, form-submission, top-navigation, popup or download privileges. Only the plugin's nonce-authorized bridge runs when document scripts are disabled. The bridge provides navigation, search, diagnostics and printing. Enabling document scripts permits local interactivity; it does not grant access to the Obsidian parent DOM or APIs.
A plugin-owned CSP is inserted before document scripts and replaces document-supplied policies. It blocks external resource loads, network connections, forms, workers and nested active documents. External links are opened through the parent bridge; vault links open in Obsidian. Use script-enabled mode only for trusted content: resource CSP is not a general-purpose guarantee against every action arbitrary JavaScript can attempt.
Remote styles/scripts/fonts, nested iframes/objects, and runtime-relative module imports are not supported. Missing resources appear in diagnostics instead of weakening isolation. Preview limits are 10 MB of HTML, 32 MB per asset, 100 MB of loaded assets, 32 import levels and 256 stylesheet references. Source mode remains available for inspection when previewing is unsuitable.
npm ci
npm run dev # watch and rebuild main.js
npm run check # typecheck, lint, unit tests, production build
npm run test:browser
npm run lint enforces Obsidian's rules for DOM creation, forbidden elements and window timers, together with type-aware checks for unsafe values. Warnings fail the check. Keep plugin styling in styles.css; the build also bundles it for the isolated preview. See the development workflow for implementation details.
Browser checks use installed Google Chrome on macOS, BROWSER_EXECUTABLE when supplied, or Playwright Chromium (npx playwright install chromium). They exercise the minified browser bundle with an Obsidian API mock; a real Obsidian desktop/mobile smoke test is still recommended before release.
Development dependency overrides keep the tooling's dependency chains patched:
@istanbuljs/load-nyc-config uses js-yaml 4.3.2+ to remove its vulnerable legacy argparse / sprintf-js chain. The loader uses the compatible load() API.obsidian API packages used during development and by the review linter use Moment 2.31.0+.Keep these overrides until the upstream packages adopt patched dependencies. The Obsidian API is external to the plugin bundle; these overrides do not replace dependencies inside the installed Obsidian app.