A little space for your ideas. Write Markdown, watch it take shape, and keep your drafts in your browser.
A first draft, a weekly plan, or a page worth sharing — source and preview, side by side.
Private Markdown workspace. Write locally, preview instantly, and copy clean HTML. No account is required and document content is never sent to an application server. Keep several browser drafts, open or download .md files, and move from source to a reusable result without leaving the page.
- Live Markdown preview rendered through a Web Worker.
- GitHub Flavored Markdown support for tables and task lists.
- Raw HTML support with DOMPurify sanitization, explicit URL hardening, and sanitized HTML copy.
- Local drafts, multiple files, and preferences stored in IndexedDB.
- Same-device draft conflict detection across tabs.
- Per-document working copies, conflict handling, and emergency recovery for multiple unsaved drafts.
- Outline, file sidebar, resizable editor/preview split, and persisted layout preferences.
- Open and download Markdown, copy Markdown or clean HTML code, use browser print / Save PDF, choose a color scheme, and open the Help dialog.
- Large document and large preview-output safeguards.
- No backend, accounts, analytics, telemetry, or remote user-content storage.
- Markdown content is stored locally in the browser's IndexedDB.
- Preferences are stored locally and normalized on load.
- A short-lived
sessionStoragebackup is used only to recover unsaved edits if the page is hidden or reloaded before IndexedDB finishes saving. - Clipboard and print actions use browser APIs and report recoverable errors when blocked.
The editor includes 19 persisted color schemes. GitHub Light is the default light scheme, and VS Code Dark+ is the default dark scheme.
Make yourself at home. Switch to Catppuccin Mocha for a softer dark workspace, or choose another palette below.
Available schemes: GitHub Light, GitHub Dark, Solarized Light, VS Code Dark+, One Dark Pro, Dracula, Catppuccin Mocha, Tokyo Night, Night Owl, Monokai, SynthWave '84, Material Palenight, Kanagawa, Rose Pine, Ayu Dark, Gruvbox Dark, Everforest Dark, Solarized Dark, and Nord.
- Markdown is parsed in a Web Worker so expensive renders do not block the main UI thread.
- Raw HTML is sanitized before it reaches
dangerouslySetInnerHTML. - Scripts, event handlers, forms, embedded frames, SVG/MathML profiles, dangerous styles, and unsafe protocols are stripped.
- External preview links open in a new tab with
noopener noreferrer; internal heading anchors stay in-page. - Image URLs are restricted to same-origin paths or safe base64 raster data images.
- Production headers enforce CSP,
X-Content-Type-Options,Referrer-Policy,Permissions-Policy,frame-src 'none',object-src 'none',form-action 'none', andframe-ancestors 'none'.
- Preact and Vite for the app shell.
- CodeMirror for the Markdown editor.
- unified, remark, and rehype for Markdown rendering.
- DOMPurify for preview sanitization.
- Vitest and Playwright for automated checks.
npm install
npm run devThe dev server binds to 127.0.0.1.
npm run devstarts the Vite dev server.npm run previewbuilds the app and serves it with Wrangler.npm run buildruns TypeScript checking and builds the app.npm run build:pagesbuilds the editor for GitHub Pages intodist-pages/.npm run build:sitebuilds the editor for GitHub Pages and assembles the full Pages site in_site/.npm testruns the Vitest suite once.npm run test:watchruns Vitest in watch mode.npm run test:e2eruns Playwright tests. Thepretest:e2escript builds the app first.npm run deploybuilds the app and deploys with Wrangler.
npm run build
npm test
npm run test:e2ePlaywright starts npm run preview -- --port 4173 at http://127.0.0.1:4173 and does not reuse an existing server.
The app has two hosts. Both serve the same editor.
| Host | URL | Source |
|---|---|---|
| GitHub Pages | https://igor-markin.github.io/live-markdown-preview/ (website) and /editor/ (editor) |
.github/workflows/pages.yml pushes the built site to the gh-pages branch on every push to main |
| Cloudflare Workers | https://live-markdown-preview.igor-markin.workers.dev/ | npm run deploy |
Drafts are stored per origin. A draft written on one host is not visible on the other host.
The landing page is static HTML in site/, in English (default), Hebrew (RTL), and Russian, with a light/dark theme toggle that follows the OS setting until the visitor picks a theme. The workflow builds the editor with vite build --mode pages (base path /live-markdown-preview/editor/, no Cloudflare plugin) and puts it in editor/ next to the landing page.
GitHub Pages cannot send custom response headers. The Pages build puts the same CSP into a <meta http-equiv="Content-Security-Policy"> tag and adds a referrer meta tag. These protections from public/_headers are not available on Pages: frame-ancestors, X-Content-Type-Options, and Permissions-Policy.
Cloudflare deployment security headers are defined in public/_headers. Vite preview is configured to serve matching security headers locally for e2e coverage.
The enforced policy includes CSP, X-Content-Type-Options, Referrer-Policy, and a restrictive Permissions-Policy.
Wrangler observability is disabled in wrangler.jsonc to keep the deployed app aligned with the no-telemetry local-first model.

