| name | markdown-to-html |
|---|---|
| description | Convert Markdown to a self-contained HTML page (one file, no external assets) or a print-ready PDF using the Secutils.dev Markdown to HTML tool. Hand the user https://tools.secutils.dev/md-to-html (optionally with the Markdown encoded in the URL fragment for one-click preload), tell them to edit in the left pane and watch the live preview, then click **Share**, **↓ HTML**, or **↓ PDF**. Trigger when the user asks to "convert this markdown to HTML", "render markdown as a printable PDF", "make a self-contained HTML page from markdown", "share a rendered markdown preview", or anything that names secutils.dev/md-to-html. |
In-browser Markdown converter with a live preview, CodeMirror-powered Markdown syntax highlighting, and three export paths:
- Share - copies a
tools.secutils.dev/md-to-html#<encoded>URL with the entire Markdown round-tripped through the URL fragment. - ↓ HTML - downloads a single self-contained HTML file (every asset inlined: fonts, syntax highlighting, optional TOC, theme toggle).
- ↓ PDF - opens the browser print dialog against a Paged.js-rendered document with proper page numbers, running titles, and break-avoid rules.
YAML frontmatter (title, author, …) is honoured; the title field
becomes the downloaded file's <title> and filename.
| Field | Type | Default | Notes |
|---|---|---|---|
markdown |
string | required | Markdown source. YAML frontmatter (---\ntitle: ...\n---) is honoured. |
The page also has an Options popover (gear icon) with three checkboxes that influence the HTML export:
| Option | Default | Effect on the generated HTML |
|---|---|---|
| Table of contents | on | Floating sidebar generated from h2/h3 headings (only shown when ≥ 3 headings exist). |
| PDF export button | on | Floating "↓ PDF" button in the top-right that calls window.print() against the inlined @media print rules. |
| Embed Markdown source | off | Appends <script type="text/markdown" id="su-md-source">…</script> to the body, retrievable via document.getElementById('su-md-source').textContent. |
Same canonical format every Secutils.dev tool uses:
| 4 bytes uncompressed-length (LE u32) | N bytes raw DEFLATE of UTF-8 markdown |
Pipeline: UTF-8 bytes of the raw Markdown → deflate-raw → prepend the
4-byte LE u32 of the uncompressed length → base64url (+→-, /→_,
strip =). The state is just the Markdown text itself - no JSON wrapper.
If the user wants to interactively edit / preview / share, hand them the plain URL:
https://tools.secutils.dev/md-to-html
If you already have their Markdown and want them to land on a pre-filled page (no copy-paste step), encode and pass it in the fragment. From any machine with Node ≥ 18:
node -e '
const zlib = require("node:zlib");
const md = process.argv[1];
const utf8 = Buffer.from(md, "utf8");
const out = Buffer.concat([Buffer.alloc(4), zlib.deflateRawSync(utf8)]);
out.writeUInt32LE(utf8.length, 0);
const enc = out.toString("base64").replace(/\+/g,"-").replace(/\//g,"_").replace(/=+$/,"");
console.log("https://tools.secutils.dev/md-to-html#" + enc);
' '# Hello
This is **markdown**.'Pass the Markdown as a single argv (single-quoted) so newlines, backticks, and shell metacharacters survive intact. Always print the full URL - the fragment is opaque and dropping a single character breaks decoding.
If the user just wants HTML in chat (not a downloadable file with the
Secutils.dev styling, TOC, and theme toggle), convert it yourself with any
Markdown library: marked, markdown-it, pandoc -t html5, etc. Use the
tool when the user wants a polished, self-contained artefact they can
email, share, or print.
If you've handed over the URL, that's the whole interaction - the user takes it from there in the browser. No follow-up encoding required.
- The Markdown only ever exists client-side - the URL fragment
(everything after
#) is never sent to the Secutils.dev server. The share link is therefore safe for content the user wouldn't want logged, but anyone who receives the link can read the source. - Embedded HTML in the Markdown is rendered as-is. Don't paste untrusted
Markdown that contains
<script>tags into a tool you're about to share with someone - that's a stored-XSS-by-helpfulness risk. - PDF rendering is paginated by Paged.js (~150 KB lazy-loaded the first time you click ↓ PDF). The PDF is a true vector PDF, not a screenshot.
- The URL fragment is bounded by browser/server URL limits (~8 KB practical ceiling). Very large documents (book-length) won't fit; suggest the user download HTML and share the file instead.
- The CodeMirror editor lazy-loads from
esm.shon first paint. If the CDN is unreachable, the page falls back to a plain<textarea>- all core functionality (live preview, share, export) still works.