This VS Code extension converts Markdown files to pdf, html, png or jpeg files.
Highlights of new features and improvements since v2. See Breaking Changes for changes that may affect existing behavior.
Markdown PDF: Output Diagnostics command for bug reports (details)Changes since v2 that may affect existing behavior. See the FAQ section for details.
markdown-pdf.sanitize: "gfm" (default) or "gfm-allow-style", block-level <style>, <script>, and <iframe> elements are now removed together with their content, instead of being escaped and left as visible text in the output. A notification reports what was removed during an export.
<script>, <iframe>, <style>, and on* / javascript: attributes are stripped from Markdown body content. The behavior is controlled by the new markdown-pdf.sanitize setting.
Markdown PDF adds the following authoring features on top of the default Markdown renderer when converting to PDF, HTML, PNG, or JPEG.
| Category | Feature | Description | Example |
|---|---|---|---|
| Basic syntax extensions | Syntax highlighting | Code block highlighting via highlight.js | ```js |
| Emoji | Emoji shortcodes | :smile: |
|
| Checkbox | GitHub-style task lists | - [ ] / - [x] |
|
| Heading IDs | GitHub-compatible heading anchors | # Heading → #heading |
|
| Content composition | Container | Admonition-like blocks | ::: warning |
| Include | Embed Markdown fragments | :[label](path.md) |
|
| Diagrams & math | PlantUML | UML diagrams from code blocks | @startuml … @enduml |
| Mermaid | Diagrams from fenced code blocks | ```mermaid |
|
| Math | LaTeX math via KaTeX | $E = mc^2$ |
Render - [ ] / - [x] task-list items as disabled checkboxes, mirroring GitHub's task list rendering. Useful for status reports and checklists that should stay visible in the exported output.
Markdown
- [ ] Task A
- [x] Task B
Preview

Headings receive GitHub-compatible anchor IDs automatically, so internal links such as [Section](#section) resolve the same way they do on GitHub. ASCII headings are lowercased with spaces replaced by hyphens; non-ASCII headings keep their original characters.
| Heading | Generated ID |
|---|---|
# My Heading |
#my-heading |
# API Reference |
#api-reference |
# 日本語見出し |
#日本語見出し |
See also: Why did my heading anchors change? in the FAQ.
Admonition-like blocks via markdown-it-container. The identifier after ::: becomes the block's CSS class, so you can style warnings, tips, and notes by pairing it with markdown-pdf.styles.
Markdown
::: warning
**Warning:** here be dragons
:::
Stylesheet (for example markdown-pdf.css)
.warning {
border-left: 4px solid #f0ad4e;
background: #fff8e1;
padding: 12px 16px;
margin: 8px 0;
}
Settings
"markdown-pdf.styles": ["markdown-pdf.css"]
Preview

See also: markdown-pdf.styles.
Embed the content of another Markdown file inline using :[alternate-text](relative-path-to-file.md). If a referenced fragment cannot be read (missing file, permission error, etc.), the extension reports the error at the include site and continues exporting the rest of the document.
Given the following directory layout (where README.md is the document being exported):
├── [plugins]
│ └── README.md
├── CHANGELOG.md
└── README.md
Markdown
README Content
:[Plugins](./plugins/README.md)
:[Changelog](CHANGELOG.md)
Preview
Content of README.md
Content of plugins/README.md
Content of CHANGELOG.md
See also: markdown-pdf.markdown-it-include.enable.
Render UML diagrams via PlantUML using markdown-it-plantuml. Two equivalent syntaxes are supported; both produce the same <img> tag and share the markdown-pdf.plantumlServer setting.
A ```plantuml fenced code block. This is the common fence convention used across the PlantUML ecosystem (for example, GitLab renders this form natively when the PlantUML integration is enabled).
Markdown
```plantuml
Bob -[#red]> Alice : hello
Alice -[#0000FF]->Bob : ok
```
@startuml / @enduml block markers. The markers can be customized via markdown-pdf.plantumlOpenMarker and markdown-pdf.plantumlCloseMarker.
Markdown
@startuml
Bob -[#red]> Alice : hello
Alice -[#0000FF]->Bob : ok
@enduml
Preview (either form produces the same image)

See also: markdown-pdf.plantumlServer.
Render diagrams from fenced code blocks via Mermaid. The Mermaid library is loaded from the URL configured in markdown-pdf.mermaidServer (defaults to a CDN).
Markdown
```mermaid
stateDiagram
[*] --> First
state First {
[*] --> second
second --> [*]
}
```
Preview

Render LaTeX math via KaTeX. Uses @vscode/markdown-it-katex (the same plugin VS Code's built-in Markdown preview ships) for $…$, $$…$$, and \begin{env}…\end{env}, plus a small in-house plugin for \(…\) and \[…\] bracket delimiters. Rendering runs in Node, so no network access is required.
Supported notations:
Inline: $E = mc^2$, \(E = mc^2\)
Display: $$\int_0^\infty f(x)\,dx$$, \[\alpha\]
LaTeX environments: \begin{aligned}a &= b\\c &= d\end{aligned}
Fenced code block:
```math
\sum_{i=1}^{n} i = \frac{n(n+1)}{2}
```
Markdown
Inline: $E = mc^2$
Display:
$$\int_0^\infty e^{-x^2}\,dx = \frac{\sqrt{\pi}}{2}$$
LaTeX environment:
\begin{aligned}
x + y &= 10 \\
x - y &= 4
\end{aligned}
Preview

See also:
This README converted to each output format:
Markdown PDF uses a Chromium-based browser for PDF/PNG/JPEG export. It tries the following sources in order:
See How is the Chromium browser selected? and Where is Chromium downloaded? in the FAQ for details.
If you are behind a proxy, set the http.proxy option in settings.json and restart Visual Studio Code.
F1 or Ctrl+Shift+Pexport and select below
markdown-pdf: Export (settings.json)markdown-pdf: Export (pdf)markdown-pdf: Export (html)markdown-pdf: Export (png)markdown-pdf: Export (jpeg)markdown-pdf: Export (all: pdf, html, png, jpeg)To collect environment information for a bug report, run Markdown PDF: Output Diagnostics. See How do I troubleshoot a failed export? in the FAQ.

markdown-pdf: Export (settings.json)markdown-pdf: Export (pdf)markdown-pdf: Export (html)markdown-pdf: Export (png)markdown-pdf: Export (jpeg)markdown-pdf: Export (all: pdf, html, png, jpeg)
"markdown-pdf.convertOnSave": true option to settings.jsonVisual Studio Code User and Workspace Settings
markdown-pdf.* settings
markdown-pdf.type"markdown-pdf.type": [
"pdf",
"html",
"png",
"jpeg"
],
markdown-pdf.convertOnSavemarkdown-pdf.convertOnSaveExclude"markdown-pdf.convertOnSaveExclude": [
"^work",
"work.md$",
"work|test",
"[0-9][0-9][0-9][0-9]-work",
"work\\test" // All '\' need to be written as '\\' (Windows)
],
markdown-pdf.outputDirectory\ need to be written as \\ (Windows)"markdown-pdf.outputDirectory": "C:\\work\\output",
Markdown file, it will be interpreted as a relative path from the filefolder, it will be interpreted as a relative path from the root folderworkspace, it will be interpreted as a relative path from each root folder
"markdown-pdf.outputDirectory": "output",
~, it will be interpreted as a relative path from the home directory"markdown-pdf.outputDirectory": "~/output",
relative path, it will be created if the directory does not existabsolute path, an error occurs if the directory does not existmarkdown-pdf.outputDirectoryRelativePathFilemarkdown-pdf.outputDirectoryRelativePathFile option is set to true, the relative path set with markdown-pdf.outputDirectory is interpreted as relative from the filemarkdown-pdf.styles\ need to be written as \\ (Windows)"markdown-pdf.styles": [
"C:\\Users\\<USERNAME>\\Documents\\markdown-pdf.css",
"/home/<USERNAME>/settings/markdown-pdf.css",
],
Markdown file, it will be interpreted as a relative path from the filefolder, it will be interpreted as a relative path from the root folderworkspace, it will be interpreted as a relative path from each root folder
"markdown-pdf.styles": [
"markdown-pdf.css",
],
~, it will be interpreted as a relative path from the home directory"markdown-pdf.styles": [
"~/.config/Code/User/markdown-pdf.css"
],
"markdown-pdf.styles": [
"https://xxx/markdown-pdf.css"
],
markdown-pdf.stylesRelativePathFilemarkdown-pdf.stylesRelativePathFile option is set to true, the relative path set with markdown-pdf.styles is interpreted as relative from the filemarkdown-pdf.includeDefaultStylesmarkdown-pdf.highlightmarkdown-pdf.highlightStylehighlight.js style file name. Examples: github.css, monokai.css, base16/solarized-dark.css"markdown-pdf.highlightStyle": "github.css",
markdown-pdf.breaksmarkdown-pdf.emojimarkdown-pdf.executablePath\ need to be written as \\ (Windows)"markdown-pdf.executablePath": "C:\\Program Files (x86)\\Google\\Chrome\\Application\\chrome.exe"
markdown-pdf.chromium.autoDownloadfalse, Markdown PDF does not download Chromium and relies only on markdown-pdf.executablePath or an installed Google Chrome / Microsoft Edge / Chromium. Export fails if none is available."markdown-pdf.chromium.autoDownload": true
markdown-pdf.scale"markdown-pdf.scale": 1
markdown-pdf.displayHeaderFooter"markdown-pdf.headerTemplate": "",
"markdown-pdf.footerTemplate": "",
markdown-pdf.headerTemplatemarkdown-pdf.displayHeaderFooter to true<span class='date'></span> : formatted print date. The format depends on the environment<span class='title'></span> : markdown file name<span class='url'></span> : markdown full path name<span class='pageNumber'></span> : current page number<span class='totalPages'></span> : total pages in the document%%ISO-DATETIME%% : current date and time in ISO-based format (YYYY-MM-DD hh:mm:ss)%%ISO-DATE%% : current date in ISO-based format (YYYY-MM-DD)%%ISO-TIME%% : current time in ISO-based format (hh:mm:ss)%%ISO-DATE%%"markdown-pdf.headerTemplate": "<div style=\"font-size: 9px; margin-left: 1cm;\"> <span class='title'></span></div> <div style=\"font-size: 9px; margin-left: auto; margin-right: 1cm; \">%%ISO-DATE%%</div>",
<span class='date'></span>"markdown-pdf.headerTemplate": "<div style=\"font-size: 9px; margin-left: 1cm;\"> <span class='title'></span></div> <div style=\"font-size: 9px; margin-left: auto; margin-right: 1cm; \"> <span class='date'></span></div>",
markdown-pdf.footerTemplate"markdown-pdf.footerTemplate": "<div style=\"font-size: 9px; margin: 0 auto;\"> <span class='pageNumber'></span> / <span class='totalPages'></span></div>",
markdown-pdf.printBackgroundmarkdown-pdf.orientationmarkdown-pdf.pageRanges"markdown-pdf.pageRanges": "1,4-",
markdown-pdf.format"markdown-pdf.format": "A4",
markdown-pdf.widthmarkdown-pdf.height"markdown-pdf.width": "10cm",
"markdown-pdf.height": "20cm",
markdown-pdf.margin.topmarkdown-pdf.margin.bottommarkdown-pdf.margin.rightmarkdown-pdf.margin.left"markdown-pdf.margin.top": "1.5cm",
"markdown-pdf.margin.bottom": "1cm",
"markdown-pdf.margin.right": "1cm",
"markdown-pdf.margin.left": "1cm",
markdown-pdf.quality"markdown-pdf.quality": 100,
markdown-pdf.clip.xmarkdown-pdf.clip.ymarkdown-pdf.clip.widthmarkdown-pdf.clip.height// x-coordinate of top-left corner of clip area
"markdown-pdf.clip.x": 0,
// y-coordinate of top-left corner of clip area
"markdown-pdf.clip.y": 0,
// width of clipping area
"markdown-pdf.clip.width": 1000,
// height of clipping area
"markdown-pdf.clip.height": 1000,
markdown-pdf.omitBackgroundmarkdown-pdf.plantumlOpenMarker@startuml / @enduml block marker syntax. Change this if you want to use a different start marker.markdown-pdf.plantumlCloseMarker@startuml / @enduml block marker syntax. Change this if you want to use a different end marker.markdown-pdf.plantumlServerdocker run -d -p 8080:8080 plantuml/plantuml-server:jetty
plantuml/plantuml-server - Docker Hubmarkdown-pdf.markdown-it-include.enablemarkdown-pdf.mermaidServermarkdown-pdf.math.enabledEnable math rendering via KaTeX for $…$, $$…$$, \(…\), \[…\], and ```math fenced code blocks.
Matches the behavior of VS Code's built-in Markdown preview.
Set to false to keep the raw $, \(, \[, and ```math text (use this if your document contains $X$-style placeholders that should not be parsed as math).
To disable math in a single document only, escape the $ as \$ at the call site, or override this setting via YAML front matter:
---
math:
enabled: false
---
boolean. Default: true
markdown-pdf.math.katex.macrosUser-defined KaTeX macros passed to the KaTeX renderer.
Example: { "\\RR": "\\mathbb{R}" }
Per-document macros can be supplied via YAML front matter, which takes precedence over this setting:
---
math:
katex:
macros:
"\\RR": "\\mathbb{R}"
---
Default: {}
markdown-pdf.sanitize"gfm": Strip GFM's disallowed tags and dangerous attributes (default)"gfm-allow-style": Same as "gfm" but keeps <style> elements"none": Disable sanitization (legacy behavior, not recommended)"gfm""markdown-pdf.sanitize": "gfm",
.emoji {
height: 2em;
}
Using files.autoGuessEncoding option of the Visual Studio Code is useful because it automatically guesses the character code. See files.autoGuessEncoding
"files.autoGuessEncoding": true,
If you always want to output to the relative path directory from the Markdown file.
For example, to output to the "output" directory in the same directory as the Markdown file, set it as follows.
"markdown-pdf.outputDirectory" : "output",
"markdown-pdf.outputDirectoryRelativePathFile": true,
Please use either of the following to insert a page break.
<div class="page"/>
<div class="page"></div>
Starting with 2.0.0, Markdown PDF generates heading IDs using a custom markdown-it-named-headers implementation that follows GitHub-compatible VS Code slug generation. Compared to the previous implementation, the new slug generator preserves CJK characters and underscores while removing unsupported punctuation, which can cause existing internal anchors (e.g. #some-heading) to resolve differently.
If your Markdown relies on specific anchor strings (for example, a table of contents or cross-document links), re-check the generated anchors after exporting and update the links as needed.
Starting with 2.0.0, Markdown PDF uses highlight.js v11 (previously v9). Some style names from v9 have been renamed or removed. Markdown PDF maps legacy style names to current names where possible and shows a warning message when a configured style cannot be found. If no mapping is available, the extension falls back to tomorrow.css.
Please check the available styles and update your markdown-pdf.highlightStyle setting to a current style name.
Starting with 2.0.0, Markdown PDF parses YAML front matter with a custom implementation instead of gray-matter. The new parser is stricter and rejects the following cases that the old parser may have accepted:
A valid front matter must be a YAML mapping (object) at the top level, for example:
---
title: My Document
"markdown-pdf":
displayHeaderFooter: true
---
BOM-prefixed files are still supported.
Earlier versions of this extension passed all raw HTML in Markdown through to the renderer without validation. Tags such as <script> and <iframe> could therefore execute during preview or PDF rendering, creating XSS-like risk when opening untrusted Markdown files (#411).
Starting with 2.1.0, raw HTML inside the Markdown body is sanitized by default per the GFM Disallowed Raw HTML extension. Behavior is controlled by markdown-pdf.sanitize:
| Mode | Behavior |
|---|---|
"gfm" (default) |
Strip GFM's disallowed tags and dangerous attributes. Recommended when opening Markdown files authored by others. |
"gfm-allow-style" |
Same as "gfm" but keeps <style> so you can embed CSS directly in a Markdown file to produce a self-contained PDF. Use only with content you trust — even without <script>, CSS can issue requests to attacker-controlled URLs via url(...) / @import / @font-face and leak information (known as CSS exfiltration). |
"none" |
Disable sanitization. Legacy behavior. Not recommended. |
What "gfm" removes
Disallowed tags:
<title>, <textarea>, <style>, <xmp>, <iframe>, <noembed>, <noframes>, <script>, <plaintext>
Starting with 2.2.0, block-level <style> / <script> / <iframe> elements are removed together with their content, so CSS or JavaScript source no longer appears as literal text in the output. All other cases — the remaining disallowed tags, and inline occurrences of any disallowed tag — have their opening < escaped to < (content preserved as visible text). In 2.1.0, everything was escaped.
Attributes:
on* event handlers (onclick, onload, …)href / src whose value starts with javascript:Sanitize notification
Starting with 2.2.0, when elements are removed or attributes are stripped during an export, a notification summarizes what was neutralized: a toast with a "Show Details" button on manual export, or an entry in the "Markdown PDF" output channel on Auto convert.
Migrating from inline <style>
If you used to customize PDF layout by writing <style> directly inside a Markdown file, move that CSS into a .css file and reference it via markdown-pdf.styles. External stylesheets are loaded from your VS Code settings, not from the Markdown body, so they are not affected by sanitization.
Caveats for external CSS:
@import url(...), background: url(...), attribute selectors with url(...), etc. Only reference stylesheet files you trust.markdown-pdf.stylesRelativePathFile is true, the stylesheet path is resolved relative to the opened Markdown file. Be cautious about opening Markdown from untrusted locations that may ship a malicious sibling .css.Sanitization scope
Sanitized:
html_block / html_inline):[label](path.md)) — it goes through the same rendererNot sanitized:
markdown-pdf.styles (by design — user-configured trust boundary)Starting with 2.2.0, the extension writes detailed logs to the Markdown PDF output channel. Open it via View > Output and select Markdown PDF in the dropdown.
Markdown PDF: Output Diagnostics from the Command Palette to print environment and configuration diagnostics: extension version, VS Code / OS information, the Chromium path and how it was selected, and relevant settings. Home directory paths are masked.When filing an issue, please attach the output of Markdown PDF: Output Diagnostics and the log shown by Show Details.
Markdown PDF resolves a Chromium-based browser in the following order:
The first match wins. The per-OS scan order for installed Edge and Chromium is:
Windows
@puppeteer/browsers)%LOCALAPPDATA%\Microsoft\Edge\Application\msedge.exe%LOCALAPPDATA%\Chromium\Application\chrome.exe%PROGRAMFILES%\Microsoft\Edge\Application\msedge.exe%PROGRAMFILES%\Chromium\Application\chrome.exe%PROGRAMFILES(X86)%\Microsoft\Edge\Application\msedge.exe%PROGRAMFILES(X86)%\Chromium\Application\chrome.exemacOS
@puppeteer/browsers)/Applications/Chromium.app/Contents/MacOS/Chromium/Applications/Microsoft Edge.app/Contents/MacOS/Microsoft EdgeLinux
@puppeteer/browsers)/usr/bin/chromium-browser/usr/bin/chromium/usr/bin/microsoft-edge/usr/bin/microsoft-edge-stableIf no installed browser is found, Markdown PDF downloads a managed Chromium on first use. The download is stored under the extension's VS Code global storage directory:
| OS | Download path |
|---|---|
| Windows | %APPDATA%\Code\User\globalStorage\yzane.markdown-pdf\ |
| macOS | ~/Library/Application Support/Code/User/globalStorage/yzane.markdown-pdf/ |
| Linux | ~/.config/Code/User/globalStorage/yzane.markdown-pdf/ |
If you use VS Code Insiders or VSCodium, the base path changes accordingly (for example Code - Insiders or VSCodium instead of Code).
During the download, Installing Chromium is shown in the status bar.
Which Chromium build is downloaded?
Markdown PDF tries to fetch the latest Chrome Stable build id from the Chrome for Testing API. The latest build id is checked once per VS Code session: when a newer Chrome Stable has been released, Markdown PDF downloads the new build at the next export and removes the previously cached build. Within the same VS Code session the build id is memoized — restart VS Code to pick up a freshly released build.
If the API is unreachable, it falls back in this order:
puppeteer-core (last-resort fallback)Disabling the auto-download
Set markdown-pdf.chromium.autoDownload to false to skip the download entirely. Markdown PDF will then rely only on markdown-pdf.executablePath or an installed Google Chrome / Microsoft Edge / Chromium, and export will fail with an error if none is available.
markdown-pdf.styles optionSee CHANGELOG.md for the full change history.
MIT
If you find Markdown PDF useful, you can support continued development via GitHub Sponsors.