A real-time markdown editor and preview tool with GitHub Flavored Markdown support. Type markdown on the left, see beautifully rendered output on the right — instantly.
- CodeMirror 6 Editor — Syntax highlighting, line numbers, undo/redo, line wrapping
- GitHub Flavored Markdown — Tables, task lists, strikethrough, fenced code blocks
- Syntax Highlighted Code — Automatic language detection via highlight.js
- XSS Protection — All output sanitized through DOMPurify
- GitHub-Quality Styling — Preview styled with github-markdown-css
- Tab System — Open multiple files in tabs (Notepad++ style), with dirty indicators (
*) - File Operations — Open/save files via native OS file picker (File System Access API)
- Dark/Light Theme — Toggle manually or auto-detect from system preference, persisted in localStorage
- Draggable Split Pane — Resize editor/preview by dragging the divider
- Layout Toggle — Overleaf-style buttons: editor-only, split, preview-only
- Divider Collapse Arrows — Quick collapse/restore with arrow buttons on the divider
- Bidirectional Scroll Sync — Editor and preview scroll together using source-line mapping
- Jump to Source — Double-click any block in the preview to jump to the corresponding editor line
- Formatting Shortcuts —
Ctrl+B(bold),Ctrl+I(italic),Ctrl+K(link) - Heading Anchors — Click headings to navigate via anchor links
- External Links — Open in new tabs with
rel="noopener noreferrer" - Real-Time Preview — 50ms debounced updates as you type
# Install dependencies
npm install
# Build and start the server (opens browser automatically)
npm startThe app runs at http://127.0.0.1:3000.
| Shortcut | Action |
|---|---|
Ctrl+O |
Open file |
Ctrl+S |
Save file (Save As if untitled) |
Ctrl+W |
Close current tab |
Ctrl+B |
Bold selection |
Ctrl+I |
Italic selection |
Ctrl+K |
Insert link |
| Command | Description |
|---|---|
npm start |
Build frontend bundle and start the Express server |
npm run build |
Build the frontend bundle only |
npm run dev |
Start the server with nodemon (auto-restart on changes) |
markdown-preview/
├── server.js # Express server — static files + file read/write API
├── build.mjs # esbuild bundler config
├── src/
│ ├── main.js # App entry — wires all modules together
│ ├── editor.js # CodeMirror 6 factory with theme compartment
│ ├── render.js # unified/remark/rehype pipeline → DOMPurify → HTML
│ ├── theme.js # Dark/light theme system with localStorage persistence
│ ├── layout.js # Draggable split pane, layout toggle, collapse/restore
│ ├── file-ops.js # Tab manager + file open/save via File System Access API
│ ├── sync.js # Bidirectional scroll sync + double-click jump-to-source
│ └── shortcuts.js # CodeMirror keymap for Ctrl+B/I/K formatting
├── public/
│ ├── index.html # Toolbar, tab bar, split pane shell with theme CSS vars
│ ├── bundle.js # (generated) frontend bundle
│ └── bundle.css # (generated) CSS bundle
└── package.json
Markdown text
→ remark-parse (parse to AST)
→ remark-gfm (tables, task lists, strikethrough)
→ remark-rehype (markdown AST → HTML AST)
→ rehypeSourceLines (inject data-source-line attributes)
→ rehype-highlight (syntax highlight code blocks)
→ rehype-slug (heading IDs for anchor links)
→ rehype-stringify (HTML AST → string)
→ External link post-processing (target="_blank")
→ DOMPurify.sanitize() (XSS protection)
→ innerHTML (render to preview pane)
| Method | Endpoint | Description |
|---|---|---|
GET |
/api/file?path=/absolute/path |
Read a file from the filesystem |
POST |
/api/file |
Write a file ({ path, content } body) |
Path validation prevents traversal attacks, null bytes, and non-absolute paths.
- Editor: CodeMirror 6
- Markdown: unified / remark / rehype
- GFM: remark-gfm
- Code Highlighting: rehype-highlight (highlight.js)
- Sanitization: DOMPurify
- Styling: github-markdown-css
- Server: Express 5
- Bundler: esbuild
ISC

