Preview MDX files in Obsidian, with first-class support for Code Hike — scrollycoding, code annotations, focus lines, and compile-time syntax highlighting — plus Mermaid diagrams.
Forked from yulei-chen/obsidian-mdx and rewritten with a security-first architecture, mobile compatibility, and offline rendering.
Most MDX-related plugins for Obsidian only handle editing — they register .mdx as a plain-text file so Obsidian stops treating it as unknown, but they don't compile or render the MDX.
MDX Preview compiles your MDX so JSX and Code Hike annotations render in a live preview. Custom React components from your own app can't be resolved by the plugin, so they show a labeled placeholder rather than breaking the whole preview. Pair it with any edit-only plugin if you want richer editor support alongside the preview.
Why not the original MDX by yulei-chen? That plugin is the foundation this one was built on. This fork adds a security-first architecture (sandboxed iframe with a consent gate), bundles the renderer at build time so no internet connection is needed, and supports mobile.
!focus, !mark, !diff, and all Code Hike annotations work out of the boxmermaid code fences render as SVG diagrams, with per-diagram errors for invalid syntax@code-hike/lighter highlighter is pure JavaScript with no native dependencies), so it works on iOS and Androidsandbox="allow-scripts" iframe with no access to your vault or Obsidian APIs/images/... paths backed by a nearby public/ folder, render in desktop and mobile preview.mdx files open directly in the preview view, no command palette step neededmain.js, manifest.json, and styles.css from the latest release..obsidian/plugins/mdx-preview/ inside your vault.Once listed, search for MDX Preview in Settings → Community Plugins → Browse and click Install.
.mdx extension — it opens automatically in the preview view.Copy this into a .mdx file to try Code Hike annotations:
export function Code({ codeblock }) {
return <pre>{codeblock.value}</pre>
}
## Annotated code
```js !focus
// !mark[/greet/] red
function greet(name) {
// !mark green
return `Hello, ${name}!`
}
```
For a full scrollycoding example, see the Code Hike vite example.
Mermaid fences render as diagrams in preview:
```mermaid
flowchart TD
A[Draft MDX] --> B[Preview in Obsidian]
B --> C[Publish]
```
MDX is executable JavaScript. This plugin takes several steps to limit the blast radius:
sandbox="allow-scripts" with no allow-same-origin, giving it a null origin — vault files and Obsidian APIs are completely unreachable from inside the iframeeval() or new Function() is used — the compiled MDX function body is embedded directly as a <script> tag, which is the same model browsers use for normal scriptsdata: URLs — the only image form that loads in a null-origin sandbox (app:// resource URLs and host-created blob: URLs are both origin-scoped and are blocked there). Because the image bytes live in the same iframe as the MDX JavaScript, a script can read the bytes of any vault image the file names (including a path it guesses) and send them over the network. This does not expose arbitrary vault files — only images the previewed file explicitly references — but it is why the rule above holds: only preview files you trust.This repo uses pnpm (see pnpm-lock.yaml).
pnpm install
pnpm dev # esbuild --watch, builds main.js + styles.css with inline sourcemaps
pnpm build # tsc -noEmit type-check, then a minified production build
To see changes in Obsidian itself, symlink (or copy) manifest.json, main.js, and styles.css into a test vault at .obsidian/plugins/mdx-preview/, then reload Obsidian. Installing the community Hot-Reload plugin in that vault saves you from restarting Obsidian after every rebuild.
pnpm test # playwright test
tests/e2e/preview.spec.ts doesn't launch real Obsidian. It bundles the iframe renderer scripts with esbuild, compiles sample MDX through the same @mdx-js/mdx + codehike/mdx pipeline the plugin uses at runtime, and injects them into a sandboxed srcdoc iframe on a Playwright page, then asserts against the rendered DOM. This covers the renderer and MDX-compile pipeline in isolation — src/main.ts and src/mdxPreview.tsx (the Obsidian view wrapper) aren't exercised by these tests, so verifying those needs the manual vault loop above.
If Playwright reports a missing browser, run pnpm exec playwright install chromium once.
Issues and pull requests are welcome at jovialio/obsidian-mdx.
The decisions behind this plugin — mobile compatibility, offline rendering, eliminating eval(), and the sandboxed security model — are documented in detail:
From Fork to Production: How I Rebuilt an Obsidian MDX Plugin
Originally forked from yulei-chen/obsidian-mdx by yulei-chen. Thank you for the foundation.
MIT — see the LICENSE file for details.