Quikdown is a small secure bidirectional markdown parser and editor for browsers and Node.js. Nine modules β use only what you need.
- quikdown.js (12.6 KB) β Markdown to HTML parser. XSS-safe, fence plugin callbacks, inline styles or CSS classes.
- quikdown_bd.js (17.4 KB) β Bidirectional: everything in core plus HTML to Markdown round-trip.
- quikdown_edit.js (89.7 KB) β Drop-in split-view editor with live preview, undo/redo, bidirectional editing, and lazy-loaded fence plugins for code highlighting, Mermaid, MathJax, SVG, CSV, GeoJSON, and STL.
- quikdown_edit_standalone.js (3.9 MB) β Offline/air-gapped editor. Same as above but bundles highlight.js, Mermaid, DOMPurify, Leaflet, and Three.js β no CDN required. See Standalone Docs.
- quikdown_mcp.js (26 KB) β MCP (Model Context Protocol) server. Exposes 24 tools for AI agents over JSON-RPC 2.0 on stdio. Works with Cursor, Claude Desktop, VS Code, and any MCP host.
- quikdown_ast.js / quikdown_json.js / quikdown_yaml.js / quikdown_ast_html.js β AST companion libraries for structured output.
Live Site | Try the Editor | Examples | Frameworks | Downloads | Docs
quikdown_edit in split mode β markdown source on the left, live rendered preview with Mermaid diagram on the right. Toolbar shows mode switching, undo/redo, copy, and linefeed controls.
- Compact markdown parser β single-pass markdown to HTML. Handles headings, lists, tables, code blocks, inline formatting, task lists, autolinks, and lazy linefeeds.
- Bidirectional editing β edit the rendered HTML and get markdown back. Round-trip preserves formatting, fences, and tables.
- Drop-in editor β one
<div>, one import. Source, split, and preview modes. Undo/redo, toolbar, copy as rich text, light/dark/auto themes. - Fence plugins β code (highlight.js), Mermaid diagrams, MathJax equations, inline SVG, CSV/TSV/PSV tables, GeoJSON maps, STL 3D models, raw HTML. All bidirectional.
- XSS-safe β HTML entities escaped by default. URL sanitization blocks
javascript:,vbscript:, and non-imagedata:URIs. - Browser and Node.js β forward parser and bidirectional parser work in both. Quikdown Editor requires DOM.
- Zero runtime deps (core) β parser and bidirectional modules have no dependencies. The editor lazy-loads fence libraries (highlight.js, Mermaid, MathJax, etc.) from CDN on demand, or use the standalone offline bundle (~3.9 MB, no CDN).
- TypeScript definitions β maintained
.d.tsfiles for all modules. - Inline styles or CSS classes β built-in light/dark themes, or bring your own CSS.
- Copy as rich text β copies the rendered preview to clipboard with images, tables, and rendered fences. Paste into Gmail, Word, Slack, Notion.
- Headless mode β run the editor without a toolbar. Wire
undo(),setTheme(),setMode()to your own UI. Rich API for controlling / selecting / manipulating markdown and rendered text with undo/redo support. - Structured output β parse markdown into AST, JSON, or YAML via companion libraries.
Quikdown is available via NPM and related unpkg and jsdelivr
npm install quikdownCDN (ES Modules):
<script type="module">
import quikdown from 'https://unpkg.com/quikdown/dist/quikdown.esm.min.js';
document.body.innerHTML = quikdown('# Hello World');
</script>CDN (UMD):
<script src="https://unpkg.com/quikdown/dist/quikdown.umd.min.js"></script>
<script>
document.body.innerHTML = quikdown('# Hello World');
</script>Quikdown is built in 3 versions. The smallest (quikdown) provides markdown to html conversion only. The next (quikdown_bd) provides markdown to html and html to markdown support. The lightweight editor quikdown_edit allows a bidirectional editor with lazy loading for common fences such as codeblocks, svg, and mermaid diagrams is also provided.
// Basic conversion
const html = quikdown('# Hello World',
{inline_styles: true} // Use inline styles, more options in API docs
);
document.body.innerHTML = html;// Convert with source tracking
const htmlString = quikdown_bd(markdown, options);
// Convert HTML back to Markdown
const markdown = quikdown_bd.toMarkdown(htmlString);Note: quikdown does not provide a generic html to markdown conversion but uses special tags and limited DOM parsing for HTML to markdown conversion. Standard markdown components such as headings, text styles, tables, quotes, etc are supported. For custom fences quikdown relies on its tag system or 3rd party handlers to provide reverse (html to md) conversion.
const editor = new QuikdownEditor('#container', {
mode: 'split', // 'source', 'split', 'preview'
theme: 'auto', // 'light', 'dark', 'auto'
plugins: { highlightjs: true, mermaid: true } // built-in fence handlers, see API docs for custom plugins
});
editor.setMarkdown('# Content \nTo be quik or not to be.'); // provide default content
const content = editor.getMarkdown(); // get source content, see APIs for getting / setting HTMLConvert markdown to structured data formats for programmatic manipulation:
import quikdown_ast from 'quikdown/ast';
import quikdown_json from 'quikdown/json';
import quikdown_yaml from 'quikdown/yaml';
import quikdown_ast_html from 'quikdown/ast-html';
const markdown = '# Hello\n\nWorld **bold**';
// Markdown β AST object
const ast = quikdown_ast(markdown);
// Markdown β JSON string
const json = quikdown_json(markdown);
// Markdown β YAML string
const yaml = quikdown_yaml(markdown);
// AST/JSON/YAML β HTML
const html = quikdown_ast_html(ast); // or pass json/yaml stringThe AST parsers are "forgiving" - they handle malformed markdown gracefully without throwing errors. See AST Documentation for the complete node type reference.
Note: The editor automatically lazy-loads plugin libraries from CDNs when needed:
- highlight.js - Loaded when code blocks are encountered and
highlightjs: true - mermaid - Loaded when mermaid diagrams are found and
mermaid: true - DOMPurify - Loaded when HTML fence blocks are rendered
- MathJax v3 - Loaded when
math,tex,latex, orkatexfence blocks are encountered (katexlang kept for backward compatibility)
This keeps the initial bundle small while providing rich functionality on-demand.
quikdown meets three common integration patterns. Pick the entry point that matches who drives the document:
| Audience | What you need | Entry point |
|---|---|---|
| Parse-only | Render markdown, AST/JSON/YAML, streaming HTML in your app | import quikdown from 'quikdown' β or quikdown/ast, quikdown/json, quikdown/yaml |
| File agents | An AI agent reads and writes .md / HTML files in a repo sandbox |
Path A: npx quikdown-mcp --root=. β IDE editing, no browser |
| Doc copilot | Human edits in a live preview; agent drives the same buffer | Path B: node examples/mcp-doc-host/start-mcp.js β browser QuikdownEditor + Node MCP bridge |
Parse-only is the default: zero config, embed anywhere. File agents add MCP filesystem tools under a --root sandbox β best when the human stays in Cursor or VS Code. Doc copilot binds the full editor surface (regex, undo, rich render export) when the human works in a browser tab.
Browser demos and streaming patterns: docs/llm-integration.md. MCP setup and tool reference: docs/quikdown-mcp.md.
quikdown fits the model writes markdown, human sees rendered output loop:
| Pattern | Doc / demo |
|---|---|
| AI Canvas β chat + document editor | examples/ai-canvas β simulated or live LLM (BYOK) |
| Agent tool calling on editor | examples/llm-tool-editor |
| MCP doc copilot (Node + browser) | examples/mcp-doc-host β 24 MCP tools via WebSocket |
| Stream into QuikdownEditor | examples/llm-stream-editor |
| Stream tokens into HTML | integration-llm-stream |
| Chat bubbles + markdown | quikchat + integration example |
Overview: docs/llm-integration.md
quikdown includes an MCP server that lets AI agents parse markdown, convert between formats, read/write files, and (with a doc host) control the editor β all over JSON-RPC 2.0.
Two paths:
| Path | Human UI | Command |
|---|---|---|
| A β IDE (shipped) | Cursor / VS Code file editor; no browser | npx quikdown-mcp --root=. |
| B β Doc copilot (shipped) | Browser tab with QuikdownEditor; Node host bridges MCP | node examples/mcp-doc-host/start-mcp.js |
Path B is a Node launcher + browser window β you work in the browser; the agent drives the same doc via MCP through Node. Setup: examples/mcp-doc-host/README.md. Overview: Path A vs Path B.
npm install quikdown
npx quikdown-mcp --root=.24 tools in three groups:
| Group | Tools | Activated by |
|---|---|---|
| Headless | markdown_to_html, html_to_markdown, markdown_stats, quikdown_info, markdown_to_ast, markdown_to_json |
Always |
| Filesystem | read_file_info, read_file_lines, read_file_markdown, write_markdown_to_file, write_html_to_file |
--root flag |
| Editor | read_editor, write_editor, find_regex, replace_regex, replace_text, extract_text, get_stats, get_html, undo, redo, load_file_to_editor, get_rendered, write_rendered_to_file |
Editor binding |
Cursor (Path A β IDE + repo files):
{
"mcpServers": {
"quikdown": { "command": "npx", "args": ["quikdown-mcp", "--root=."] }
}
}Cursor (Path B β doc copilot, from quikdown repo): run npm run build first, then:
{
"mcpServers": {
"quikdown-doc": {
"command": "node",
"args": ["examples/mcp-doc-host/start-mcp.js"]
}
}
}Opens a browser tab with QuikdownEditor; you edit in the browser while the agent uses MCP. See examples/mcp-doc-host/README.md.
Claude Desktop (Path A):
{
"mcpServers": {
"quikdown": { "command": "npx", "args": ["quikdown-mcp", "--root=."] }
}
}Programmatic:
import { createMcpServer } from 'quikdown/mcp';
const mcp = createMcpServer({ root: '.' });
const result = mcp.callTool('markdown_to_html', { markdown: '# Hello' });Full documentation: docs/quikdown-mcp.md | MCP setup page
quikdown supports built-in styles for a "batteries included" experience or you can bring your own CSS themes. Example css files are provided for basic light and dark themes to get started.
const html = quikdown(markdown, {
lazy_linefeeds: true, // Single newlines become <br>
inline_styles: false, // Use class based CSS instead of inline styles
fence_plugin: { // Custom code block processor (v1.1.0+ API)
render: myHandler // Function to render fence blocks
}
});Inline styles: All formatting uses inline CSS
quikdown('**bold**', { inline_styles: true });
// <strong style="font-weight: bold;">bold</strong>Class-based styling: Uses CSS classes (default)
quikdown('**bold**');
// <strong>bold</strong>
// Requires CSS: .quikdown strong { font-weight: bold; }
// see included dist/quikdown.light.css or quikdown.dark.cssQuikdown provides a callback for all fenced text such as code blocks, math, svg etc.
Handle code blocks with custom languages:
const fencePlugin = {
render: (code, language) => {
if (language === 'mermaid') {
// Process with mermaid library and return rendered diagram
const id = 'mermaid-' + Math.random().toString(36).substr(2, 9);
setTimeout(() => mermaid.render(id + '-svg', code).then(result => {
document.getElementById(id).innerHTML = result.svg;
}), 0);
return `<div id="${id}" class="mermaid">Loading diagram...</div>`;
}
// Return undefined for default handling
}
};
const html = quikdown(markdown, { fence_plugin: fencePlugin });quikdown includes TypeScript definitions for better IDE support and type safety:
import quikdown, { QuikdownOptions, FencePlugin } from 'quikdown';
const fencePlugin: FencePlugin = {
render: (content: string, language: string) => {
return `<pre class="hljs ${language}">${content}</pre>`;
}
};
const options: QuikdownOptions = {
inline_styles: true,
fence_plugin: fencePlugin
};
const html: string = quikdown(markdown, options);Text formatting: **bold**, *italic*, ~~strikethrough~~, `code`
Headings: # H1 through ###### H6
Lists:
- Unordered lists
- Ordered lists
- Task lists
Links: [text](url) and automatic URL detection
Code blocks:
console.log('syntax highlighting support via plugins');Tables, blockquotes, horizontal rules - See documentation for complete syntax reference
For complete API documentation, see docs/api-reference.md
All HTML is escaped by default. Only safe markdown constructs become HTML:
const unsafe = '<script>alert("XSS")</script> **bold**';
const safe = quikdown(unsafe);
// <script>alert("XSS")</script> <strong>bold</strong>Static analysis β quikdown passes ESLint with eslint-plugin-security at error level with zero findings. All regex patterns are verified free of catastrophic backtracking (ReDoS), and no dynamic RegExp construction is used. Security lint is enforced in CI on every build.
For the full security model, see docs/security.md.
Works with React, Vue, Svelte, Angular. See Framework Integration Guide. For LLM/agent patterns (streaming, tool editor), see LLM Integration.
For size and security, quikdown doesn't support:
- Reference-style links
- Footnotes
- Definition lists
Optional heading slugs: pass heading_ids: true to add id attributes on headings for in-page anchor links.
Note that raw html, svg, etc can be rendered using appropriate fences
<h1>My HTML Content</h1>
<p>Some HTML</p>as long as an appropriate fence plugin is provided. See API docs for example or try out in quikdown_edit.js which has built-in support for HTML with XSS prevention.
BSD 2-Clause - see LICENSE.txt
- Inspired by the simplicity of early markdown parsers
- Built for the QuikChat project
- CommonMark spec for markdown standardization
- π Documentation
- π Issues
- π¦ Examples hub Β· examples/ (source)