<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Usman</title>
    <description>The latest articles on DEV Community by Usman (@usmankhan45).</description>
    <link>https://dev.to/usmankhan45</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.us-east-2.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F4002260%2Fb8fdf296-ae5e-48f7-b0b8-ee234ad10131.png</url>
      <title>DEV Community: Usman</title>
      <link>https://dev.to/usmankhan45</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/usmankhan45"/>
    <language>en</language>
    <item>
      <title>Excel or Google Sheets to a Markdown Table, the Fast Way</title>
      <dc:creator>Usman</dc:creator>
      <pubDate>Tue, 03 Nov 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/usmankhan45/excel-or-google-sheets-to-a-markdown-table-the-fast-way-19e</link>
      <guid>https://dev.to/usmankhan45/excel-or-google-sheets-to-a-markdown-table-the-fast-way-19e</guid>
      <description>&lt;p&gt;Hand-typing a Markdown table from a spreadsheet is the kind of task that takes ten minutes and produces one misaligned pipe you only notice after pushing. There's a much faster route, and it works because of how spreadsheets put data on your clipboard.&lt;/p&gt;

&lt;p&gt;Converting an Excel or Google Sheets table to Markdown takes three steps: select and copy the cells in your spreadsheet, paste them into a &lt;a href="https://www.mdtool.dev/markdown-table-generator" rel="noopener noreferrer"&gt;Markdown table generator&lt;/a&gt;, and copy the generated Markdown. Spreadsheets place copied cells on the clipboard as tab-separated text, so a converter can rebuild the rows and columns exactly, with no add-in, export step, or upload required.&lt;/p&gt;

&lt;p&gt;This guide covers that workflow end to end: why the clipboard trick works, what survives the conversion (and what doesn't), and how to fix the three things that most often break spreadsheet-sourced tables in Markdown.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Copy-Paste Works: The Tab-Separated Clipboard
&lt;/h2&gt;

&lt;p&gt;When you copy a range of cells in Excel, Google Sheets, LibreOffice Calc, or Numbers, the spreadsheet writes two versions to your clipboard: a rich one (HTML) and a plain-text one. The plain-text version separates columns with tab characters and rows with newlines, a format called TSV (tab-separated values).&lt;/p&gt;

&lt;p&gt;That plain-text version is what a Markdown table generator reads. Each tab becomes a column boundary, each line becomes a row, and the first row is treated as the header. Because tabs almost never appear &lt;em&gt;inside&lt;/em&gt; spreadsheet cell content, TSV parsing is far more reliable than CSV parsing, where commas inside values (like "1,000" or "Portland, OR") routinely split cells in the wrong place.&lt;/p&gt;

&lt;p&gt;The practical consequence: &lt;strong&gt;you don't need an Excel add-in or a file exporter&lt;/strong&gt; to get Markdown out of a spreadsheet. The clipboard already contains everything the conversion needs.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Workflow, Step by Step
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Select the cells&lt;/strong&gt; in Excel or Google Sheets (include the header row).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy&lt;/strong&gt; them (Ctrl+C / Cmd+C).&lt;/li&gt;
&lt;li&gt;Open the &lt;a href="https://www.mdtool.dev/markdown-table-generator" rel="noopener noreferrer"&gt;Markdown Table Generator&lt;/a&gt; and click &lt;strong&gt;Paste from Excel / CSV&lt;/strong&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paste&lt;/strong&gt;. The grid fills with your data, first row as the header.&lt;/li&gt;
&lt;li&gt;Adjust anything that needs it: click the alignment control above a column to align it left, center, or right (numbers usually read better right-aligned).&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Copy the output&lt;/strong&gt; as Markdown, or flip the toggle to HTML if the destination is a web page or CMS rather than a README.&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;The result is a GitHub Flavored Markdown table with padded columns, so the raw text stays readable in a code editor:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Product   | Q1 Revenue | Growth |
|-----------|-----------:|-------:|
| Converter |    $12,400 |    18% |
| Generator |     $8,100 |    31% |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Everything happens in the browser. The cells you paste are parsed locally and never uploaded, which matters more for spreadsheets than for most documents: financial data, customer lists, and internal metrics are exactly the content you don't want passing through a stranger's server.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Survives the Conversion (and What Doesn't)
&lt;/h2&gt;

&lt;p&gt;Markdown tables are intentionally simpler than spreadsheets, so the conversion keeps the content but drops spreadsheet-specific machinery:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Spreadsheet feature&lt;/th&gt;
&lt;th&gt;In Markdown&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Cell text and numbers&lt;/td&gt;
&lt;td&gt;Preserved exactly&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Header row&lt;/td&gt;
&lt;td&gt;Becomes the Markdown header&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Column order&lt;/td&gt;
&lt;td&gt;Preserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Formulas&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Only the computed value carries over: &lt;code&gt;=SUM(B2:B9)&lt;/code&gt; pastes as its result&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;strong&gt;Cell formatting&lt;/strong&gt; (colors, borders, fonts)&lt;/td&gt;
&lt;td&gt;Dropped. Markdown tables have no styling syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Merged cells&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Not supported. The value lands in one cell, the rest are empty&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;Multiple lines in a cell&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;Converted to &lt;code&gt;&amp;lt;br&amp;gt;&lt;/code&gt;, which GitHub renders correctly&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you need merged cells or styling, generate the HTML output instead and edit the markup. Markdown's table syntax has no colspan or style attributes, and no generator can add what the format doesn't support. The &lt;a href="https://www.mdtool.dev/markdown-cheat-sheet/tables" rel="noopener noreferrer"&gt;Markdown table syntax guide&lt;/a&gt; covers these limits in detail.&lt;/p&gt;

&lt;h2&gt;
  
  
  The Three Fixes You'll Actually Need
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;1. Numbers columns look ragged.&lt;/strong&gt; Spreadsheets right-align numbers automatically; Markdown defaults to left. After pasting, set numeric columns to right alignment. In the generated syntax that's a trailing colon in the separator row (&lt;code&gt;---:&lt;/code&gt;), and it makes financial or metric tables dramatically easier to scan.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;2. Pipe characters in cell content.&lt;/strong&gt; A cell containing &lt;code&gt;|&lt;/code&gt; would break the table's column structure. A good generator escapes them as &lt;code&gt;\|&lt;/code&gt; automatically; if you're converting by hand, this is the first thing to check when a table renders with misplaced columns.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;3. Thousands separators split cells in CSV.&lt;/strong&gt; If you're importing a &lt;em&gt;CSV file&lt;/em&gt; rather than pasting copied cells, values like &lt;code&gt;1,000&lt;/code&gt; split into two columns because the comma is the delimiter. The fix is to copy the cells from the spreadsheet directly (tab-separated) instead of exporting to CSV first, one of several reasons paste-from-spreadsheet beats the export route.&lt;/p&gt;

&lt;h2&gt;
  
  
  When You Need More Than a Table
&lt;/h2&gt;

&lt;p&gt;A table generator is the right tool when the table &lt;em&gt;is&lt;/em&gt; the content: a comparison in a README, benchmark results in an issue, a pricing grid in documentation. When the table is embedded in a larger document, convert the whole document instead:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;A full Word document with tables in it → &lt;a href="https://www.mdtool.dev/word-to-markdown" rel="noopener noreferrer"&gt;Word to Markdown converter&lt;/a&gt;. Tables convert along with headings, lists, and links, as covered in the &lt;a href="https://www.mdtool.dev/blog/docx-to-markdown" rel="noopener noreferrer"&gt;DOCX to Markdown guide&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;A finished Markdown document going the other way, into a PDF → the &lt;a href="https://www.mdtool.dev/markdown-to-pdf" rel="noopener noreferrer"&gt;Markdown to PDF converter&lt;/a&gt; renders GFM tables natively. If your tables have broken in PDF exports before, &lt;a href="https://www.mdtool.dev/blog/markdown-table-pdf" rel="noopener noreferrer"&gt;this guide explains why&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;Markdown tables destined for a web page → the &lt;a href="https://www.mdtool.dev/markdown-to-html" rel="noopener noreferrer"&gt;Markdown to HTML converter&lt;/a&gt; turns them into real &lt;code&gt;&amp;lt;table&amp;gt;&lt;/code&gt; markup with &lt;code&gt;thead&lt;/code&gt; and &lt;code&gt;tbody&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I convert an Excel table to Markdown?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Select and copy the cells in Excel, then paste them into MDTool's free Markdown Table Generator using its "Paste from Excel / CSV" option. Excel copies cells as tab-separated text, so the grid rebuilds your rows and columns exactly, and you copy the result as a finished Markdown table.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does this work with Google Sheets?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, identically. Google Sheets, LibreOffice Calc, and Apple Numbers all copy selected cells as tab-separated plain text, which is the format the importer reads.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Do Excel formulas convert to Markdown?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No, only the computed values. The clipboard's plain-text version contains what the cell displays, not the formula behind it. A cell showing 42 from &lt;code&gt;=A1*2&lt;/code&gt; pastes as 42.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is my spreadsheet data uploaded when I convert it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not with MDTool. The paste import and table generation run entirely in your browser. The data never leaves your device, which you can verify by watching the Network tab in your browser's developer tools while converting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I keep merged cells from my spreadsheet?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Markdown tables can't represent merged cells. Switch the generator's output to HTML and add &lt;code&gt;colspan&lt;/code&gt;/&lt;code&gt;rowspan&lt;/code&gt; attributes by hand, or restructure the table so each cell holds its own value, usually the better option for READMEs.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://www.mdtool.dev" rel="noopener noreferrer"&gt;MDTool&lt;/a&gt;, the free browser converter used in this post. It's &lt;a href="https://github.com/usmankhan045/mdtool" rel="noopener noreferrer"&gt;open source&lt;/a&gt; (MIT), so if something breaks in it, open an issue or tell me in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>github</category>
      <category>productivity</category>
      <category>excel</category>
    </item>
    <item>
      <title>Migrating a CMS from HTML to Markdown: What Survives and What Breaks</title>
      <dc:creator>Usman</dc:creator>
      <pubDate>Tue, 27 Oct 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/usmankhan45/migrating-a-cms-from-html-to-markdown-what-survives-and-what-breaks-f16</link>
      <guid>https://dev.to/usmankhan45/migrating-a-cms-from-html-to-markdown-what-survives-and-what-breaks-f16</guid>
      <description>&lt;p&gt;Moving a site from a database-backed CMS to Markdown files sounds simple until you look at the HTML your old CMS has been storing: inline styles, page-builder divs, shortcodes, merged table cells. Some of it converts perfectly; some of it has no Markdown equivalent at all.&lt;/p&gt;

&lt;p&gt;Here's what to expect before you migrate a content library, and the cleanup pass that saves you from fixing every page by hand.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Teams Migrate From HTML CMS to Markdown
&lt;/h2&gt;

&lt;p&gt;Migrating away from an HTML-based CMS toward a Markdown workflow is one of the most common reasons people go looking for an HTML-to-Markdown converter. It's not because Markdown is trendy, but because the destination platforms specifically want it. &lt;strong&gt;Notion&lt;/strong&gt; treats Markdown as its native import and export format. &lt;strong&gt;Ghost&lt;/strong&gt;'s post editor is Markdown-first under the hood, even though it renders HTML on the published page. Static site generators (&lt;strong&gt;Astro&lt;/strong&gt;, &lt;strong&gt;Hugo&lt;/strong&gt;, &lt;strong&gt;Jekyll&lt;/strong&gt;, and others) build entire sites from Markdown (or MDX) files committed to a Git repository, with no database involved at all.&lt;/p&gt;

&lt;p&gt;The draw is consistent across all of these destinations: content lives in version-controllable plain-text files instead of a database table, there's no plugin ecosystem to patch and maintain, and the files themselves are portable: a Markdown file isn't tied to one platform's theme CSS the way an HTML export can be.&lt;/p&gt;

&lt;p&gt;The friction point is almost always the same, though: your existing content already exists as HTML, exported from WordPress, copied from a documentation site, or sitting in a CMS with no native Markdown export. That's the actual conversion this guide walks through.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Converts Cleanly and What Does Not
&lt;/h2&gt;

&lt;p&gt;Set honest expectations before you commit to converting an entire content library, because HTML is more expressive than Markdown and some things genuinely don't survive the trip.&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Source HTML&lt;/th&gt;
&lt;th&gt;Result&lt;/th&gt;
&lt;th&gt;Notes&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Headings, paragraphs, bold/italic&lt;/td&gt;
&lt;td&gt;✅ Converts cleanly&lt;/td&gt;
&lt;td&gt;Maps directly to Markdown syntax&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Links and images&lt;/td&gt;
&lt;td&gt;✅ Converts cleanly&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;href&lt;/code&gt;, &lt;code&gt;src&lt;/code&gt;, and &lt;code&gt;alt&lt;/code&gt; preserved as-is&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Ordered/unordered lists, incl. nesting&lt;/td&gt;
&lt;td&gt;✅ Converts cleanly&lt;/td&gt;
&lt;td&gt;Indentation follows CommonMark rules&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Straightforward GFM tables&lt;/td&gt;
&lt;td&gt;✅ Converts cleanly&lt;/td&gt;
&lt;td&gt;Simple row/column tables only&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Fenced code blocks&lt;/td&gt;
&lt;td&gt;✅ Converts cleanly&lt;/td&gt;
&lt;td&gt;Language tag kept if source has &lt;code&gt;class="language-js"&lt;/code&gt;
&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Inline styles, presentation-only &lt;code&gt;&amp;lt;span&amp;gt;&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;❌ Dropped&lt;/td&gt;
&lt;td&gt;No Markdown equivalent to preserve them in&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;
&lt;code&gt;colspan&lt;/code&gt;/&lt;code&gt;rowspan&lt;/code&gt;, nested tables&lt;/td&gt;
&lt;td&gt;⚠️ Flattened&lt;/td&gt;
&lt;td&gt;GFM tables can't express merged cells&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Embedded JS widgets, iframes, galleries&lt;/td&gt;
&lt;td&gt;❌ Dropped&lt;/td&gt;
&lt;td&gt;No Markdown representation exists&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Expanded CMS shortcodes (e.g. WordPress galleries)&lt;/td&gt;
&lt;td&gt;⚠️ Needs manual rebuild&lt;/td&gt;
&lt;td&gt;Leaves div-based layout markup with no Markdown equivalent&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If your source documents are actually Word files rather than HTML pages, the &lt;a href="https://www.mdtool.dev/word-to-markdown" rel="noopener noreferrer"&gt;Word to Markdown converter&lt;/a&gt; handles that format directly rather than requiring an HTML export step first.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step Migration With MDTool
&lt;/h2&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Get the HTML.&lt;/strong&gt; Use View Source or Inspect Element on a live page, your CMS's HTML export feature, or a WordPress XML export converted to per-page HTML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Convert.&lt;/strong&gt; Paste the HTML into the &lt;a href="https://www.mdtool.dev/html-to-markdown" rel="noopener noreferrer"&gt;HTML to Markdown converter&lt;/a&gt;, or upload the &lt;code&gt;.html&lt;/code&gt; file directly via drag-and-drop.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Check the high-risk areas first.&lt;/strong&gt; Tables and code blocks are where conversion most often needs a second pass, so verify those before trusting the rest of the page.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Save with the filename and structure your destination expects.&lt;/strong&gt; Copy the Markdown or download it as &lt;code&gt;.md&lt;/code&gt;. Note that MDTool converts body content only. Hugo, Jekyll, and Astro all expect YAML front matter (title, date, slug) at the top of the file, which you'll need to add separately since it isn't represented as visible page content in the source HTML.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Repeat per page.&lt;/strong&gt; For a handful of pages, this paste-based workflow is the fastest path. For a migration spanning dozens or hundreds of pages, script the conversion against the underlying &lt;code&gt;turndown&lt;/code&gt; library directly rather than pasting one page at a time. It's the same logic MDTool uses, but callable in a loop.&lt;/li&gt;
&lt;/ol&gt;

&lt;h2&gt;
  
  
  Cleaning Up the Output After Conversion
&lt;/h2&gt;

&lt;p&gt;A few issues show up reliably enough across CMS migrations that it's worth checking for them specifically, the same way developers converting &lt;a href="https://www.mdtool.dev/blog/github-readme-to-pdf" rel="noopener noreferrer"&gt;GitHub READMEs to PDF&lt;/a&gt; check badges and Mermaid diagrams before trusting a batch export:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Missing front matter.&lt;/strong&gt; Every Markdown-based platform needs metadata MDTool doesn't generate, so add title, date, and slug fields manually or with a small script per platform.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Near-empty Markdown tables.&lt;/strong&gt; Layout-only HTML tables from page-builder plugins sometimes convert into a pipe table with little real content, so delete these rather than trying to repair them.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Broken relative image paths.&lt;/strong&gt; An image path that resolved correctly on the old CMS often won't resolve on the new platform's folder structure. Re-point these to wherever you're now hosting images; most static site generators expect them in a &lt;code&gt;static/&lt;/code&gt; or &lt;code&gt;public/&lt;/code&gt; folder.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Stray emphasis markers.&lt;/strong&gt; HTML that applies bold via both a CSS class and a real &lt;code&gt;&amp;lt;strong&amp;gt;&lt;/code&gt; tag can occasionally produce doubled-up &lt;code&gt;**&lt;/code&gt; characters. Proofread the first converted page closely before applying the same workflow across the rest of the migration.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Can MDTool migrate an entire WordPress site at once?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. MDTool converts one page of HTML at a time, in your browser. For migrating an entire site, export each page's HTML, convert pages individually, or script the conversion against the underlying &lt;code&gt;turndown&lt;/code&gt; library if you need to process many files programmatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does converted Markdown include front matter for Hugo or Jekyll?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. MDTool converts the body content of the HTML (headings, text, tables, code), not metadata. You'll need to add YAML front matter (title, date, slug, tags) manually or with a separate script, since that data isn't represented as visible content in the source HTML.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What happens to WordPress shortcodes during conversion?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Shortcode syntax itself (&lt;code&gt;[gallery ids="1,2,3"]&lt;/code&gt;) is usually already expanded into plain HTML by the time you copy a rendered page, so the bracket syntax won't appear, but the resulting div-based layout markup has no Markdown equivalent and needs to be manually rebuilt using your new platform's image or component syntax.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I convert HTML exported from Notion into Markdown for a different platform?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Notion already exports to Markdown natively, so for Notion content specifically you usually don't need an HTML-to-Markdown step at all. Reach for HTML conversion only when Markdown export isn't available for the specific content type you're working with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does the converted Markdown work with MDX, for Astro or Gatsby?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Standard Markdown output is also valid MDX, since MDX is a superset of Markdown syntax. You may still need to manually convert any embedded interactive widgets into actual JSX components, since those have no Markdown representation to begin with.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Will my page's CSS classes carry over?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No, and that's intentional. CSS classes are presentation, not content, and Markdown has no syntax to represent them. Your new platform applies its own styling to the converted Markdown.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I handle internal links between migrated pages?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Links convert as-is, including their original &lt;code&gt;href&lt;/code&gt; values. After migration, you'll likely need to update those hrefs to match your new platform's URL structure. That's a find-and-replace pass, not something the converter can infer automatically.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is it safe to convert pages with customer data or unpublished drafts?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. MDTool's conversion runs entirely in your browser via JavaScript; nothing is uploaded to a server, so unpublished or sensitive content never leaves your device during conversion.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://www.mdtool.dev" rel="noopener noreferrer"&gt;MDTool&lt;/a&gt;, the free browser converter used in this post. It's &lt;a href="https://github.com/usmankhan045/mdtool" rel="noopener noreferrer"&gt;open source&lt;/a&gt; (MIT), so if something breaks in it, open an issue or tell me in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>webdev</category>
      <category>cms</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Markdown to PDF Without Breaking Your Code Blocks</title>
      <dc:creator>Usman</dc:creator>
      <pubDate>Tue, 20 Oct 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/usmankhan45/markdown-to-pdf-without-breaking-your-code-blocks-3f2e</link>
      <guid>https://dev.to/usmankhan45/markdown-to-pdf-without-breaking-your-code-blocks-3f2e</guid>
      <description>&lt;p&gt;If you've exported technical docs from Markdown to PDF, you've probably seen it: code in a proportional font, no highlighting, lines running off the page, indentation gone. The prose comes through fine and the code, the part your readers actually need, doesn't.&lt;/p&gt;

&lt;p&gt;Here's why that happens and how to get code blocks into a PDF intact.&lt;/p&gt;

&lt;h2&gt;
  
  
  How do you convert Markdown to PDF with syntax highlighting for code blocks?
&lt;/h2&gt;

&lt;p&gt;Give every fenced code block a language tag (&lt;code&gt;&lt;/code&gt;&lt;code&gt;python `, `&lt;/code&gt;&lt;code&gt;js&lt;/code&gt;), paste the Markdown into a converter that highlights code in the PDF itself, and download. In &lt;a href="https://www.mdtool.dev/markdown-to-pdf" rel="noopener noreferrer"&gt;MDTool's Markdown to PDF converter&lt;/a&gt; that's three steps:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Paste your Markdown. Check that each code fence names its language.&lt;/li&gt;
&lt;li&gt;Pick a theme: GitHub, Academic, Minimal or Dark. Each one has its own highlight palette, so keywords, strings, numbers and comments are colored differently in the PDF.&lt;/li&gt;
&lt;li&gt;Click &lt;strong&gt;Download PDF&lt;/strong&gt;. Code keeps its indentation and colors, Mermaid blocks (&lt;code&gt;&lt;/code&gt;`&lt;code&gt;mermaid&lt;/code&gt;) become real diagrams, and the whole conversion runs in your browser, so the code is never uploaded.&lt;/li&gt;
&lt;/ol&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;What you need&lt;/th&gt;
&lt;th&gt;How MDTool handles it&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Colored syntax&lt;/td&gt;
&lt;td&gt;highlight.js tokens with a palette per theme&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Languages&lt;/td&gt;
&lt;td&gt;JavaScript, TypeScript, Python, Bash, CSS, HTML/XML, JSON, YAML, SQL, Rust, Go, Dart&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Monospace font&lt;/td&gt;
&lt;td&gt;Courier for code in standard Latin characters&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Indentation&lt;/td&gt;
&lt;td&gt;Leading spaces preserved&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Long lines&lt;/td&gt;
&lt;td&gt;Wrapped to the page instead of cut off&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Diagrams&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&lt;/code&gt;&lt;code&gt;&lt;/code&gt;mermaid ` blocks rendered as diagrams&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Selectable text&lt;/td&gt;
&lt;td&gt;Yes: the PDF contains real text, not a screenshot&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Page breaks&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;&amp;lt;!-- pagebreak --&amp;gt;&lt;/code&gt;, &lt;code&gt;\pagebreak&lt;/code&gt;, &lt;code&gt;\newpage&lt;/code&gt; or &lt;code&gt;&amp;lt;div class="page-break"&amp;gt;&amp;lt;/div&amp;gt;&lt;/code&gt; on its own line&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;If you need this in a script or CI job instead, MDTool has no CLI; see &lt;a href="https://www.mdtool.dev/blog/markdown-to-pdf-python-pandoc" rel="noopener noreferrer"&gt;Markdown to PDF with Python, Pandoc and Node&lt;/a&gt; for command-line options with highlighting.&lt;/p&gt;




&lt;h2&gt;
  
  
  Why Code Blocks Are the Hardest Part of Markdown to PDF Conversion
&lt;/h2&gt;

&lt;p&gt;If you've ever tried to convert a Markdown file with code blocks into a PDF, you've almost certainly run into at least one of these problems:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Monospace font not used, so code renders in the same proportional font as body text&lt;/li&gt;
&lt;li&gt;No syntax highlighting, so everything is plain black text&lt;/li&gt;
&lt;li&gt;Lines overflow the page and get cut off&lt;/li&gt;
&lt;li&gt;Indentation is lost, making code unreadable&lt;/li&gt;
&lt;li&gt;Background color disappears, so code blocks look identical to normal paragraphs&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;These aren't random bugs. They happen because most tools take a shortcut: they parse Markdown into HTML, then dump it into a PDF renderer that ignores CSS entirely. Code blocks depend heavily on CSS (&lt;code&gt;font-family: monospace&lt;/code&gt;, &lt;code&gt;white-space: pre&lt;/code&gt;, &lt;code&gt;overflow-x: auto&lt;/code&gt;, background colors), and when CSS is stripped out, code becomes unreadable.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Broken Code Blocks Look Like
&lt;/h2&gt;

&lt;p&gt;Here's a concrete example. Take this simple JavaScript function in a Markdown file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;javascript
&lt;/span&gt;&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchUser&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`/api/users/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;id&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;User not found&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;response&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;```&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;A &lt;strong&gt;broken PDF converter&lt;/strong&gt; will output something like this in the PDF:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;async function fetchUser(id) { const response = await fetch("/api/users/" + id); if (!response.ok) throw new Error("User not found"); return response.json(); }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;No line breaks. No monospace. No background. Just a wall of text that's impossible to read.&lt;/p&gt;

&lt;p&gt;A &lt;strong&gt;correct PDF converter&lt;/strong&gt; preserves:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The monospace font (&lt;code&gt;Courier&lt;/code&gt;, &lt;code&gt;Fira Code&lt;/code&gt;, or similar)&lt;/li&gt;
&lt;li&gt;Each line on its own line with proper indentation&lt;/li&gt;
&lt;li&gt;A light gray or dark background that visually separates code from prose&lt;/li&gt;
&lt;li&gt;Syntax-colored tokens (keywords, strings, functions) if it supports highlighting&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  The Real Code Example
&lt;/h2&gt;

&lt;p&gt;Here's the full JavaScript snippet we'll use to test PDF output throughout this guide:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight javascript"&gt;&lt;code&gt;&lt;span class="c1"&gt;// Illustrative example: a minimal browser-side Markdown to PDF function.&lt;/span&gt;
&lt;span class="c1"&gt;// (Not MDTool's own code; MDTool builds a vector PDF with pdfmake instead.)&lt;/span&gt;
&lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;convertMarkdownToPDF&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdownContent&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="c1"&gt;// Parse Markdown into an HTML string&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="nx"&gt;marked&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;marked&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;htmlContent&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="nx"&gt;marked&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;parse&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;markdownContent&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

  &lt;span class="c1"&gt;// Wrap in a styled document for proper PDF rendering&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;styledHTML&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="s2"&gt;`
    &amp;lt;!DOCTYPE html&amp;gt;
    &amp;lt;html&amp;gt;
      &amp;lt;head&amp;gt;
        &amp;lt;style&amp;gt;
          body { font-family: Georgia, serif; line-height: 1.6; }
          pre  { background: #f4f4f4; padding: 1rem; border-radius: 4px; overflow-x: auto; }
          code { font-family: 'Courier New', monospace; font-size: 0.9em; }
        &amp;lt;/style&amp;gt;
      &amp;lt;/head&amp;gt;
      &amp;lt;body&amp;gt;&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;htmlContent&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;lt;/body&amp;gt;
    &amp;lt;/html&amp;gt;
  `&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

  &lt;span class="c1"&gt;// Use html2pdf.js (browser only - never run server-side)&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;html2pdf&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="k"&gt;import&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;html2pdf.js&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;)).&lt;/span&gt;&lt;span class="k"&gt;default&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nf"&gt;html2pdf&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;set&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt; &lt;span class="na"&gt;margin&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;10&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;filename&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="s2"&gt;output.pdf&lt;/span&gt;&lt;span class="dl"&gt;"&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="na"&gt;html2canvas&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt; &lt;span class="na"&gt;scale&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="mi"&gt;2&lt;/span&gt; &lt;span class="p"&gt;}&lt;/span&gt; &lt;span class="p"&gt;})&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="k"&gt;from&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;styledHTML&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;save&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Notice the three things that make this work: the &lt;code&gt;&amp;lt;pre&amp;gt;&lt;/code&gt; element gets a background and padding, &lt;code&gt;code&lt;/code&gt; gets a monospace font, and &lt;code&gt;html2pdf.js&lt;/code&gt; is imported dynamically so it only ever runs in the browser, never on the server where &lt;code&gt;window&lt;/code&gt; is undefined.&lt;/p&gt;

&lt;p&gt;The catch with this approach is that &lt;code&gt;html2pdf.js&lt;/code&gt; takes a picture of the page with &lt;code&gt;html2canvas&lt;/code&gt;. The code in the PDF is an image: you can't select or search it, and it blurs when you zoom. That's why MDTool switched to &lt;code&gt;pdfmake&lt;/code&gt;, which writes the code into the PDF as real text, with the highlight colors applied to each token.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step: Convert Markdown with Code Blocks to PDF
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Paste Your Markdown
&lt;/h3&gt;

&lt;p&gt;Open a converter that highlights code in the PDF itself, such as &lt;a href="https://www.mdtool.dev/markdown-to-pdf" rel="noopener noreferrer"&gt;MDTool's Markdown to PDF&lt;/a&gt;, and paste your Markdown. Your code blocks should be fenced with triple backticks and include a language identifier:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;```javascript
// your code here
```
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Language identifiers like &lt;code&gt;javascript&lt;/code&gt;, &lt;code&gt;python&lt;/code&gt;, &lt;code&gt;bash&lt;/code&gt;, &lt;code&gt;typescript&lt;/code&gt;, and &lt;code&gt;json&lt;/code&gt; enable syntax highlighting. Without one, the converter tries to guess the language, which works for common code but is less reliable, so tag your fences.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 2: Check the Live Preview
&lt;/h3&gt;

&lt;p&gt;The preview panel renders your Markdown in real time. Before downloading, verify that:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Code blocks have a distinct background&lt;/li&gt;
&lt;li&gt;Indentation is preserved (4-space indents should look like 4 spaces, not 1)&lt;/li&gt;
&lt;li&gt;Long lines wrap correctly or have a horizontal scrollbar hint&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;If the preview looks right, the PDF will match, because the converter uses the same rendered HTML for both.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Choose a Theme (Optional)
&lt;/h3&gt;

&lt;p&gt;Light themes (GitHub, Academic, Minimal) work best for printed PDFs because they use dark text on a white or light-gray code background, exactly what you'd expect on paper. Dark themes look great on screen but can waste toner and reduce readability when physically printed.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Download the PDF
&lt;/h3&gt;

&lt;p&gt;Click &lt;strong&gt;Download PDF&lt;/strong&gt;. The conversion happens entirely in your browser using &lt;code&gt;pdfmake&lt;/code&gt;, so your Markdown never leaves your machine, and no server processes it.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Tip:&lt;/strong&gt; For technical documentation, use the GitHub theme. It matches the code block style developers already recognize from GitHub READMEs.&lt;/p&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  Common Problems and Fixes
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Problem: Code lines are cut off at the right edge of the page&lt;/strong&gt;&lt;br&gt;
Fix: Make sure your code lines are under ~80 to 90 characters. The converter wraps very long lines, but it can't reformat code logic. Break long lines manually before converting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem: Syntax highlighting doesn't appear&lt;/strong&gt;&lt;br&gt;
Fix: Add a language tag after the opening triple backtick. &lt;code&gt;&lt;/code&gt;&lt;code&gt;js ` instead of just `&lt;/code&gt;&lt;code&gt;&lt;/code&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem: Indentation collapses to a single space&lt;/strong&gt;&lt;br&gt;
Fix: Use spaces, not tabs. Some PDF renderers collapse tab characters. Replace tabs with 2 or 4 spaces.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem: Code block background is hard to see when printed&lt;/strong&gt;&lt;br&gt;
Fix: Every theme gives code blocks a tinted background and a border, but the light themes use a very pale gray that some printers barely show. Academic has the darkest code border of the light themes. For on-screen reading, the Dark theme gives the strongest contrast.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Problem: A Mermaid diagram shows up as code&lt;/strong&gt;&lt;br&gt;
Fix: The fence must be tagged exactly &lt;code&gt;&lt;/code&gt;`&lt;code&gt;mermaid&lt;/code&gt;. If the diagram has a syntax error, the block stays as code; check the live preview, which shows the same result the PDF will.&lt;/p&gt;

&lt;h2&gt;
  
  
  How MDTool Handles Code Blocks Differently
&lt;/h2&gt;

&lt;p&gt;Most online Markdown-to-PDF converters run on the server: they accept your Markdown, process it with a headless browser or a PDF library, and return a file. The problem is CSS support in these pipelines is inconsistent, especially for code blocks.&lt;/p&gt;

&lt;p&gt;MDTool takes a different approach. The entire conversion runs &lt;strong&gt;client-side in your browser&lt;/strong&gt; using &lt;code&gt;pdfmake&lt;/code&gt;. This means:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Real text, not a screenshot&lt;/strong&gt;: code in the PDF is selectable, searchable and sharp at any zoom&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;No data sent to a server&lt;/strong&gt;: your code stays on your machine&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Consistent output&lt;/strong&gt;: the preview and the PDF come from the same rendered HTML, with highlight colors carried into the PDF and Mermaid diagrams drawn before the PDF is built&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;This is especially important for code blocks, which depend on whitespace, a monospace font and per-token colors that many converters discard.&lt;/p&gt;

&lt;p&gt;For GitHub READMEs specifically, check out our guide on &lt;a href="https://www.mdtool.dev/blog/github-readme-to-pdf" rel="noopener noreferrer"&gt;converting GitHub READMEs to PDF&lt;/a&gt;. It covers badge handling and image-heavy READMEs alongside code blocks. If you need a refresher on fenced code block syntax itself, see the &lt;a href="https://www.mdtool.dev/markdown-cheat-sheet" rel="noopener noreferrer"&gt;Markdown cheatsheet&lt;/a&gt;.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Does MDTool support syntax highlighting for all programming languages?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;It supports JavaScript, TypeScript, Python, Bash, JSON, YAML, HTML/XML, CSS, SQL, Go, Rust and Dart. The underlying parser uses &lt;a href="https://marked.js.org/" rel="noopener noreferrer"&gt;&lt;code&gt;marked&lt;/code&gt;&lt;/a&gt; with &lt;a href="https://highlightjs.org/" rel="noopener noreferrer"&gt;&lt;code&gt;highlight.js&lt;/code&gt;&lt;/a&gt; for token coloring. If your language isn't highlighted, formatting (monospace font, background, indentation) is still preserved, and only color tokens are skipped.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Will the code block look the same in the PDF as in the preview?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Very close. The PDF is built from the same rendered HTML you see in the preview, with the same token colors, indentation and diagrams. Fonts can differ slightly: code uses Courier in the PDF, and long lines wrap to fit the page.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I convert a file with hundreds of lines of code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Because the PDF is built as text rather than as an image, long files stay small and sharp. Very large documents take longer to build in the browser, so for files with thousands of lines of code, split them into sections or use page breaks to keep each section readable.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: My code has backticks inside the code block. How do I escape them?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Use four backticks to open and close the fenced block instead of three. This allows triple backticks inside the block without escaping.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is there a file size limit?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;There's no server-side limit because conversion happens in your browser. The practical limit is your device's RAM, and most modern machines handle Markdown files up to several megabytes without issue.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I use MDTool for confidential code?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Because conversion is entirely client-side, your code is never transmitted to any server. You can use it for proprietary or sensitive code with confidence.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://www.mdtool.dev" rel="noopener noreferrer"&gt;MDTool&lt;/a&gt;, the free browser converter used in this post. It's &lt;a href="https://github.com/usmankhan045/mdtool" rel="noopener noreferrer"&gt;open source&lt;/a&gt; (MIT), so if something breaks in it, open an issue or tell me in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>markdown</category>
      <category>pdf</category>
      <category>documentation</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>Moving Word Docs into Obsidian Without Breaking Your Vault</title>
      <dc:creator>Usman</dc:creator>
      <pubDate>Tue, 13 Oct 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/usmankhan45/moving-word-docs-into-obsidian-without-breaking-your-vault-52oc</link>
      <guid>https://dev.to/usmankhan45/moving-word-docs-into-obsidian-without-breaking-your-vault-52oc</guid>
      <description>&lt;p&gt;Most of my notes live in Obsidian, but a lot of what I need to keep arrives as Word documents: specs, meeting notes, policies. Dropping a &lt;code&gt;.docx&lt;/code&gt; into the vault does nothing useful, and a naive conversion gives you a file that sits outside the graph with no backlinks.&lt;/p&gt;

&lt;p&gt;This is the workflow I use to get Word documents into a vault properly, including the Obsidian-specific cleanup that most conversion guides skip.&lt;/p&gt;

&lt;h2&gt;
  
  
  Why Obsidian Users Want Their Word Docs in Markdown
&lt;/h2&gt;

&lt;p&gt;Obsidian stores every note as a plain &lt;code&gt;.md&lt;/code&gt; file in a folder on your local filesystem, with no proprietary database, no lock-in, just text files you can open with any editor. That design choice is the reason Obsidian's knowledge graph, backlinks, and search all work without a server: the vault is just a directory. It has also driven the growth of the &lt;a href="https://obsidian.md/plugins" rel="noopener noreferrer"&gt;Obsidian community plugin directory&lt;/a&gt;, which lists over 1,000 third-party extensions as of 2026, all of them built on top of plain &lt;code&gt;.md&lt;/code&gt; files precisely because the format can be extended without breaking compatibility.&lt;/p&gt;

&lt;p&gt;Word's &lt;code&gt;.docx&lt;/code&gt; format doesn't fit this model. A &lt;code&gt;.docx&lt;/code&gt; file is a ZIP archive of XML, so it can't be opened in Obsidian, linked to from another note, or indexed by the graph view. Converting it to Markdown puts the content where Obsidian can reach it: in a plain &lt;code&gt;.md&lt;/code&gt; file that participates in your vault's link structure and shows up in search.&lt;/p&gt;

&lt;p&gt;The conversion is a one-way step. Once the note lives in your vault as a &lt;code&gt;.md&lt;/code&gt; file, you maintain it there. If stakeholders or clients need a Word version later, the &lt;a href="https://www.mdtool.dev/markdown-to-word" rel="noopener noreferrer"&gt;Markdown to Word converter&lt;/a&gt; handles the reverse direction.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Obsidian-Flavored Markdown Needs
&lt;/h2&gt;

&lt;p&gt;This is the part that most conversion guides skip: Obsidian uses a superset of standard Markdown. The converter outputs valid GitHub Flavored Markdown, which is correct and readable in Obsidian, but it doesn't produce the Obsidian-specific syntax that activates the features most users rely on.&lt;/p&gt;

&lt;p&gt;Here's what standard converter output looks like vs. what Obsidian natively uses:&lt;/p&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Feature&lt;/th&gt;
&lt;th&gt;What MDTool produces (GFM)&lt;/th&gt;
&lt;th&gt;What Obsidian expects (native)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Internal note links&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Note Title](note-title.md)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;
&lt;code&gt;[[Note Title]]&lt;/code&gt; wikilink&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Link with display name&lt;/td&gt;
&lt;td&gt;&lt;code&gt;[Display Name](note.md)&lt;/code&gt;&lt;/td&gt;
&lt;td&gt;`[[Note Title\&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Callouts / admonitions&lt;/td&gt;
&lt;td&gt;{% raw %}&lt;code&gt;&amp;gt; plain blockquote&lt;/code&gt;
&lt;/td&gt;
&lt;td&gt;&lt;code&gt;&amp;gt; [!note] Title&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Tags&lt;/td&gt;
&lt;td&gt;Not produced&lt;/td&gt;
&lt;td&gt;Inline &lt;code&gt;#tag&lt;/code&gt; or &lt;code&gt;tags:&lt;/code&gt; in YAML&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Properties / frontmatter&lt;/td&gt;
&lt;td&gt;Not produced&lt;/td&gt;
&lt;td&gt;YAML block at top of file&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Highlights&lt;/td&gt;
&lt;td&gt;Not produced&lt;/td&gt;
&lt;td&gt;&lt;code&gt;==highlighted text==&lt;/code&gt;&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;The important framing here: &lt;strong&gt;standard GFM links still work in Obsidian&lt;/strong&gt;, and a &lt;code&gt;[Note](note.md)&lt;/code&gt; link will navigate correctly. They just don't appear as connections in the graph view or show up as backlinks. Wikilinks (&lt;code&gt;[[Note Title]]&lt;/code&gt;) are what Obsidian's graph draws edges for.&lt;/p&gt;

&lt;p&gt;Whether you need wikilinks depends on how you use Obsidian. If you're importing standalone reference documents (a spec, a policy, a report) you'll reference but not heavily interlink, standard GFM output is fine as-is. If you're building a connected knowledge base where the graph view matters, plan to convert internal references to wikilinks after conversion.&lt;/p&gt;

&lt;h2&gt;
  
  
  Step-by-Step: Converting a Word Document With MDTool
&lt;/h2&gt;

&lt;p&gt;The fastest path to a vault-ready &lt;code&gt;.md&lt;/code&gt; file:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;strong&gt;Open&lt;/strong&gt; your &lt;code&gt;.docx&lt;/code&gt; file in Word and accept all tracked changes (Review → Accept → Accept All Changes). The converter outputs only the accepted text, so unresolved tracked changes will silently disappear.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Go to&lt;/strong&gt; the &lt;a href="https://www.mdtool.dev/word-to-markdown" rel="noopener noreferrer"&gt;word to markdown converter&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Drag and drop&lt;/strong&gt; the &lt;code&gt;.docx&lt;/code&gt; file onto the left panel, or click the file picker.&lt;/li&gt;
&lt;li&gt;The converter reads the document using &lt;a href="https://github.com/mwilliamson/mammoth.js" rel="noopener noreferrer"&gt;mammoth.js&lt;/a&gt;, extracting heading styles, bold/italic, lists, tables, and hyperlinks, then renders GitHub Flavored Markdown via &lt;a href="https://github.com/mixmark-io/turndown" rel="noopener noreferrer"&gt;turndown&lt;/a&gt;.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Download the &lt;code&gt;.md&lt;/code&gt; file&lt;/strong&gt; using the Download button, or copy the Markdown and paste it into a new file in your vault.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Move the &lt;code&gt;.md&lt;/code&gt; file into your vault folder&lt;/strong&gt; by dragging it in Finder/Explorer to the correct location in your vault's directory structure.&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  Alternative: The Docxer Plugin
&lt;/h3&gt;

&lt;p&gt;If you want to convert Word documents without leaving Obsidian, the &lt;a href="https://github.com/Developer-Mike/obsidian-docxer" rel="noopener noreferrer"&gt;Docxer community plugin&lt;/a&gt; (83,988 downloads, v2.3.1, actively maintained as of May 2026) lets you open a &lt;code&gt;.docx&lt;/code&gt; file directly inside a vault tab and convert it with a single click. It uses the same mammoth.js + turndown pipeline under the hood, so the output is equivalent to what MDTool produces.&lt;/p&gt;

&lt;p&gt;Install from Settings → Community Plugins → Browse → search "Docxer". One limitation worth knowing: Docxer's output is standard Markdown, not Obsidian-flavored wikilinks, so the post-conversion steps below still apply.&lt;/p&gt;

&lt;h2&gt;
  
  
  Post-Conversion Cleanup for Obsidian
&lt;/h2&gt;

&lt;p&gt;A converted &lt;code&gt;.md&lt;/code&gt; file is readable in Obsidian immediately, but five steps make it a proper vault citizen:&lt;/p&gt;

&lt;h3&gt;
  
  
  1. Add YAML Frontmatter (Properties)
&lt;/h3&gt;

&lt;p&gt;Obsidian 1.4+ renders a YAML properties block at the top of any note as an interactive panel. Add it at the very start of the file:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight yaml"&gt;&lt;code&gt;&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;span class="na"&gt;title&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;Your Document Title&lt;/span&gt;
&lt;span class="na"&gt;tags&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;imported&lt;/span&gt;
  &lt;span class="pi"&gt;-&lt;/span&gt; &lt;span class="s"&gt;word&lt;/span&gt;
&lt;span class="na"&gt;source&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;original-filename.docx&lt;/span&gt;
&lt;span class="na"&gt;created&lt;/span&gt;&lt;span class="pi"&gt;:&lt;/span&gt; &lt;span class="s"&gt;2026-06-25&lt;/span&gt;
&lt;span class="nn"&gt;---&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Obsidian will index the &lt;code&gt;tags:&lt;/code&gt; values and make them searchable across your vault. The &lt;code&gt;source:&lt;/code&gt; field is useful if you need to trace the note back to its origin.&lt;/p&gt;

&lt;h3&gt;
  
  
  2. Convert Links to Wikilinks (for Graph View)
&lt;/h3&gt;

&lt;p&gt;Find any &lt;code&gt;[text](filename.md)&lt;/code&gt; links in the converted output that point to other notes in your vault. Convert them to wikilink syntax: &lt;code&gt;[[filename]]&lt;/code&gt; or &lt;code&gt;[[filename|display text]]&lt;/code&gt;. This is what makes connections appear in Obsidian's graph view and backlinks panel.&lt;/p&gt;

&lt;p&gt;If the document doesn't reference other vault notes (it's a standalone import), skip this step entirely.&lt;/p&gt;

&lt;h3&gt;
  
  
  3. Upgrade Blockquotes to Callouts (Optional)
&lt;/h3&gt;

&lt;p&gt;The converter outputs Word text boxes and some formatting as plain Markdown blockquotes (&lt;code&gt;&amp;gt; text&lt;/code&gt;). Obsidian supports 13 callout types that render as styled admonition boxes:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="gt"&gt;&amp;gt; [!note] Title&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Content here&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!warning] Caution&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; Something to watch out for&lt;/span&gt;
&lt;span class="gt"&gt;
&amp;gt; [!tip]&lt;/span&gt;
&lt;span class="gt"&gt;&amp;gt; A helpful tip&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;If the original document had note boxes or warning panels, upgrading the corresponding blockquotes to callouts takes a few seconds per item and significantly improves readability in Obsidian's Live Preview mode.&lt;/p&gt;

&lt;h3&gt;
  
  
  4. Check Image Paths
&lt;/h3&gt;

&lt;p&gt;Word embeds images as binary objects inside the &lt;code&gt;.docx&lt;/code&gt; ZIP. MDTool keeps them, but &lt;strong&gt;inline&lt;/strong&gt;: each image becomes a long base64 &lt;code&gt;data:&lt;/code&gt; link (&lt;code&gt;![](data:image/png;base64,...)&lt;/code&gt;) instead of a separate file in your vault. That makes the note heavy and awkward to edit, so swap them for real attachment files:&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Export images from the Word document (right-click → Save as Picture)&lt;/li&gt;
&lt;li&gt;Copy the image files into a subfolder in your vault (e.g., &lt;code&gt;/attachments/&lt;/code&gt; or &lt;code&gt;/assets/&lt;/code&gt;)&lt;/li&gt;
&lt;li&gt;Add the image references in the Markdown: &lt;code&gt;![[image.png]]&lt;/code&gt; (Obsidian wikilink embed) or &lt;code&gt;![alt text](attachments/image.png)&lt;/code&gt; (standard Markdown)&lt;/li&gt;
&lt;/ol&gt;

&lt;h3&gt;
  
  
  5. Add Inline Tags or a Folder Tag
&lt;/h3&gt;

&lt;p&gt;For vault organization, either add &lt;code&gt;#tags&lt;/code&gt; inline in the note body where relevant, or put the note in a folder and create a folder note (&lt;code&gt;_index.md&lt;/code&gt;) that links to all imported documents in that folder. This helps avoid a pile of disconnected files after bulk imports.&lt;/p&gt;

&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I open a .docx file directly in Obsidian without converting it?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Obsidian only renders files in its supported formats: Markdown (&lt;code&gt;.md&lt;/code&gt;), Canvas (&lt;code&gt;.canvas&lt;/code&gt;), and a handful of image/audio/video/PDF types. A &lt;code&gt;.docx&lt;/code&gt; file will appear in the vault's file list but will not render. You must convert it to &lt;code&gt;.md&lt;/code&gt; first.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does the converted Markdown show up in Obsidian's graph view?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;The note itself shows up in the graph once it's in the vault. Its links only appear as graph edges if the links use &lt;code&gt;[[wikilink]]&lt;/code&gt; syntax. Standard &lt;code&gt;[text](url)&lt;/code&gt; links are not drawn as connections. Convert internal note references to wikilinks if graph visibility matters.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Is Obsidian Sync safe for vault files converted from Word?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Obsidian Sync uses AES-256 end-to-end encryption (confirmed on the official pricing page, $4/month billed annually). The converted &lt;code&gt;.md&lt;/code&gt; files are treated identically to any other vault file: they sync the same way and are encrypted in transit and at rest.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What happens to headers, bullet lists, and bold text after conversion?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;These convert cleanly. Word's Heading 1 style becomes &lt;code&gt;# H1&lt;/code&gt; in Markdown, bullet lists become &lt;code&gt;- item&lt;/code&gt;, and bold text becomes &lt;code&gt;**bold**&lt;/code&gt;. The conversion preserves structural styles: it reads what Word explicitly marks as a heading, not what looks like a heading visually.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: What about footnotes in Word documents?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;They aren't lost: the converter turns Word footnotes into a numbered list at the end of the note, with &lt;code&gt;[1]&lt;/code&gt;-style links where each one was referenced. Obsidian also supports Markdown footnote syntax (&lt;code&gt;[^1]&lt;/code&gt;), which renders as proper footnotes in reading view, so you can convert the list to that syntax by hand if you prefer.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I convert a batch of Word files at once?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Not through MDTool (one file at a time). The Docxer plugin also processes files individually. For bulk imports, the command line is the right tool: &lt;code&gt;pandoc *.docx --to=markdown&lt;/code&gt; with a shell loop, or &lt;a href="https://github.com/microsoft/markitdown" rel="noopener noreferrer"&gt;Microsoft MarkItDown&lt;/a&gt; (Python, batch-capable, MIT licensed) for programmatic pipelines.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Will the converted file appear in Obsidian search?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes, immediately. Obsidian indexes all &lt;code&gt;.md&lt;/code&gt; files in the vault on startup and re-indexes continuously. A freshly dropped &lt;code&gt;.md&lt;/code&gt; file is searchable within seconds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: My Word document used colors to indicate status (red = draft, green = approved). Will that survive?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;No. Font color and highlight color are presentational properties with no Markdown equivalent. They are dropped during conversion. If status markup matters, add Obsidian tags (&lt;code&gt;#draft&lt;/code&gt;, &lt;code&gt;#approved&lt;/code&gt;) to the YAML frontmatter after conversion instead.&lt;/p&gt;




&lt;p&gt;For Markdown syntax reference after importing, see the &lt;a href="https://www.mdtool.dev/markdown-cheat-sheet" rel="noopener noreferrer"&gt;Markdown cheatsheet&lt;/a&gt;. If you need to convert back to Word for sharing with non-Obsidian users, the &lt;a href="https://www.mdtool.dev/markdown-to-word" rel="noopener noreferrer"&gt;Markdown to Word converter&lt;/a&gt; handles the reverse direction.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://www.mdtool.dev" rel="noopener noreferrer"&gt;MDTool&lt;/a&gt;, the free browser converter used in this post. It's &lt;a href="https://github.com/usmankhan045/mdtool" rel="noopener noreferrer"&gt;open source&lt;/a&gt; (MIT), so if something breaks in it, open an issue or tell me in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>obsidian</category>
      <category>markdown</category>
      <category>productivity</category>
      <category>writing</category>
    </item>
    <item>
      <title>How to Download a GitHub README as PDF (Badges, Tables and Mermaid Included)</title>
      <dc:creator>Usman</dc:creator>
      <pubDate>Tue, 06 Oct 2026 13:30:00 +0000</pubDate>
      <link>https://dev.to/usmankhan45/how-to-download-a-github-readme-as-pdf-badges-tables-and-mermaid-included-5392</link>
      <guid>https://dev.to/usmankhan45/how-to-download-a-github-readme-as-pdf-badges-tables-and-mermaid-included-5392</guid>
      <description>&lt;p&gt;Every so often someone asks me for "the docs as a PDF": a client, a reviewer, a manager who wants to read it on a plane. The docs are a GitHub README, and GitHub has no "Download as PDF" button. Printing the page from the browser drags in GitHub's navigation, and most converters quietly break the parts that matter: badges vanish, tables collapse and Mermaid diagrams come out as raw code.&lt;/p&gt;

&lt;p&gt;Here's the workflow I use, plus fixes for the three things that usually go wrong: private repos, relative image paths and wide tables.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;The short version:&lt;/strong&gt; open &lt;code&gt;README.md&lt;/code&gt;, click &lt;strong&gt;Raw&lt;/strong&gt;, copy everything, paste it into a GFM-aware Markdown to PDF converter, pick a GitHub-style theme and download.&lt;/p&gt;

&lt;h2&gt;
  
  
  What Makes GitHub READMEs Different from Ordinary Markdown
&lt;/h2&gt;

&lt;p&gt;A typical README contains several elements that generic Markdown parsers struggle with:&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Badge images.&lt;/strong&gt; Lines like &lt;code&gt;![Build](https://img.shields.io/github/actions/workflow/status/...)&lt;/code&gt; fetch images from &lt;a href="https://shields.io/" rel="noopener noreferrer"&gt;shields.io&lt;/a&gt; and similar external URLs. Server-side converters often block external requests; browser-based tools load them normally.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Fenced code blocks with language tags.&lt;/strong&gt; GitHub renders these with syntax highlighting. A PDF converter needs to do the same, not just preserve the raw text.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;GFM tables.&lt;/strong&gt; Pipe-delimited tables (&lt;code&gt;| Col1 | Col2 |&lt;/code&gt;) only work if the parser has GFM mode enabled. Standard CommonMark parsers ignore them entirely.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Task lists.&lt;/strong&gt; &lt;code&gt;- [x] Done&lt;/code&gt; and &lt;code&gt;- [ ] Todo&lt;/code&gt; syntax renders as checkboxes on GitHub. A GFM-aware converter renders them as actual checkbox characters; others render them as literal brackets.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Mermaid diagrams.&lt;/strong&gt; GitHub natively renders &lt;code&gt;mermaid&lt;/code&gt; code fences as diagrams. Most PDF tools don't support this at all.&lt;/p&gt;




&lt;h2&gt;
  
  
  Step-by-Step: GitHub README to PDF
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Step 1: Get the Raw Markdown
&lt;/h3&gt;

&lt;p&gt;On any GitHub repository page, click the file name of &lt;code&gt;README.md&lt;/code&gt; (or &lt;code&gt;README.mdx&lt;/code&gt;), then click &lt;strong&gt;Raw&lt;/strong&gt; in the top-right toolbar. You'll see the plain Markdown source. Select all (&lt;code&gt;Ctrl+A&lt;/code&gt;) and copy it.&lt;/p&gt;

&lt;p&gt;Alternatively, you can download the raw file directly:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;curl &lt;span class="nt"&gt;-o&lt;/span&gt; README.md https://raw.githubusercontent.com/user/repo/main/README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;h3&gt;
  
  
  Step 2: Paste Into MDTool
&lt;/h3&gt;

&lt;p&gt;Open a browser-based converter such as &lt;a href="https://www.mdtool.dev/markdown-to-pdf" rel="noopener noreferrer"&gt;MDTool's Markdown to PDF&lt;/a&gt; and paste your README. The live preview on the right renders immediately, and you'll see headings, tables, code blocks, and badges appear in real time.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 3: Check Badges and External Images
&lt;/h3&gt;

&lt;p&gt;Badges (&lt;code&gt;shields.io&lt;/code&gt;, &lt;code&gt;github.com/actions/...&lt;/code&gt;) are standard &lt;code&gt;&amp;lt;img&amp;gt;&lt;/code&gt; tags in the rendered HTML. Because MDTool runs in your browser, those images load normally from their external URLs, the same way they load on GitHub. You should see them in the preview.&lt;/p&gt;

&lt;p&gt;If a badge doesn't appear, it's usually because:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;The image URL requires authentication (private repo badges)&lt;/li&gt;
&lt;li&gt;The external server is rate-limiting requests&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;In those cases, either remove the badge row before converting or replace the URL with a static image URL that doesn't require auth.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 4: Select a Theme
&lt;/h3&gt;

&lt;p&gt;The &lt;strong&gt;GitHub&lt;/strong&gt; theme in MDTool follows GitHub's own rendering style: dark body text, blue links, light-gray code backgrounds, and bordered tables. If you want the PDF to look as close to GitHub's rendered view as possible, use the GitHub theme. The other themes are Academic, Minimal and Dark, and every theme works with A4 or Letter paper.&lt;/p&gt;

&lt;h3&gt;
  
  
  Step 5: Download the PDF
&lt;/h3&gt;

&lt;p&gt;Click &lt;strong&gt;Download PDF&lt;/strong&gt;. The entire conversion runs in your browser, so your README content is never uploaded to any server.&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Mermaid tip:&lt;/strong&gt; MDTool renders Mermaid diagrams before it builds the PDF, so the flowchart, sequence diagram or ER diagram you see in the preview appears in the PDF output.&lt;/p&gt;
&lt;/blockquote&gt;




&lt;h2&gt;
  
  
  Handling Common README Elements
&lt;/h2&gt;

&lt;h3&gt;
  
  
  Code Blocks
&lt;/h3&gt;

&lt;p&gt;GitHub READMEs frequently include multi-language code blocks. MDTool uses &lt;code&gt;highlight.js&lt;/code&gt; with GFM mode, supporting JavaScript, TypeScript, Python, Bash, Go, Rust, SQL, JSON, YAML, HTML, CSS, Dart and more.&lt;/p&gt;

&lt;p&gt;A block like this:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;typescript
&lt;/span&gt;&lt;span class="k"&gt;export&lt;/span&gt; &lt;span class="k"&gt;async&lt;/span&gt; &lt;span class="kd"&gt;function&lt;/span&gt; &lt;span class="nf"&gt;fetchRepo&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="kr"&gt;string&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="p"&gt;{&lt;/span&gt;
  &lt;span class="kd"&gt;const&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="k"&gt;await&lt;/span&gt; &lt;span class="nf"&gt;fetch&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`https://api.github.com/repos/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;owner&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;/&lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;repo&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;if &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;!&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ok&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt; &lt;span class="k"&gt;throw&lt;/span&gt; &lt;span class="k"&gt;new&lt;/span&gt; &lt;span class="nc"&gt;Error&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;`GitHub API error: &lt;/span&gt;&lt;span class="p"&gt;${&lt;/span&gt;&lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;status&lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;`&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
  &lt;span class="k"&gt;return&lt;/span&gt; &lt;span class="nx"&gt;res&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nf"&gt;json&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;```&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Renders with full syntax coloring: keywords, strings, types, and function names each get distinct colors, exactly as they appear on GitHub.&lt;/p&gt;

&lt;h3&gt;
  
  
  Tables
&lt;/h3&gt;

&lt;p&gt;GFM tables convert cleanly. A README table like:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;| Feature       | Status |
|---------------|--------|
| Code blocks   | ✅     |
| Mermaid       | ✅     |
| Badges        | ✅     |
| Task lists    | ✅     |
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Will appear as a properly bordered, styled table in the PDF, not as a pipe-delimited text wall.&lt;/p&gt;

&lt;h3&gt;
  
  
  Mermaid Diagrams
&lt;/h3&gt;

&lt;p&gt;Project architecture diagrams in READMEs are often written in Mermaid. MDTool initializes the Mermaid renderer in the browser before the PDF export step, so:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;```&lt;/span&gt;&lt;span class="nl"&gt;mermaid
&lt;/span&gt;&lt;span class="sb"&gt;graph LR
  PR[Pull Request] --&amp;gt; CI[GitHub Actions]
  CI --&amp;gt;|Pass| Merge[Merge to main]
  CI --&amp;gt;|Fail| Fix[Fix &amp;amp; Re-push]&lt;/span&gt;
&lt;span class="p"&gt;```&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;Renders as an actual diagram in the PDF, not as a code block with raw Mermaid syntax.&lt;/p&gt;

&lt;h3&gt;
  
  
  Task Lists
&lt;/h3&gt;



&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="p"&gt;-&lt;/span&gt; [x] Set up CI pipeline
&lt;span class="p"&gt;-&lt;/span&gt; [x] Write unit tests
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Add integration tests
&lt;span class="p"&gt;-&lt;/span&gt; [ ] Deploy to production
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;MDTool's GFM parser recognizes task lists. In the PDF, each checkbox is drawn as a bold monospace &lt;code&gt;[x]&lt;/code&gt; (done) or &lt;code&gt;[ ]&lt;/code&gt; (to do), so the status stays readable even when printed in black and white.&lt;/p&gt;




&lt;h2&gt;
  
  
  Private repositories and READMEs with images
&lt;/h2&gt;

&lt;p&gt;The three-step method works the same for a private repository, because you copy the Markdown while you're signed in to GitHub and nothing about the conversion needs repository access. Two things behave differently, though.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Getting the file from the command line.&lt;/strong&gt; &lt;code&gt;raw.githubusercontent.com&lt;/code&gt; URLs for private repos need authentication, so a plain &lt;code&gt;curl&lt;/code&gt; returns a 404. Use the GitHub CLI, which calls the REST API's &lt;a href="https://docs.github.com/en/rest/repos/contents" rel="noopener noreferrer"&gt;Get a repository README&lt;/a&gt; endpoint with your credentials:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight shell"&gt;&lt;code&gt;gh api repos/OWNER/REPO/readme &lt;span class="nt"&gt;-H&lt;/span&gt; &lt;span class="s2"&gt;"Accept: application/vnd.github.raw+json"&lt;/span&gt; &lt;span class="o"&gt;&amp;gt;&lt;/span&gt; README.md
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;&lt;strong&gt;Images.&lt;/strong&gt; Images stored in a private repository can't be fetched by anyone who isn't signed in with access, and the image links GitHub generates for private content are short-lived signed URLs. An image URL you copy from the rendered page may work for a few minutes and then break. For a PDF that keeps its images:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;Move the images somewhere public you control (a docs site, a public assets repo, or an object storage bucket) and point the Markdown at those URLs, or&lt;/li&gt;
&lt;li&gt;Remove the images and describe them in text if the PDF is going to an audience that only needs the content.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;Badges (&lt;code&gt;shields.io&lt;/code&gt; and similar) are public images, so they usually load fine even for private repositories. Status badges that query a private repo's CI may show "unknown" or fail to load, and deleting the badge row before converting is the quickest fix.&lt;/p&gt;




&lt;h2&gt;
  
  
  Relative image paths: use raw.githubusercontent.com URLs
&lt;/h2&gt;

&lt;p&gt;GitHub recommends &lt;a href="https://docs.github.com/en/repositories/managing-your-repositorys-settings-and-features/customizing-your-repository/about-readmes" rel="noopener noreferrer"&gt;relative links for images&lt;/a&gt; in READMEs, such as &lt;code&gt;![Architecture](docs/architecture.png)&lt;/code&gt;. GitHub resolves those paths against the repository and branch you're viewing. Once you copy the Markdown out of GitHub, there's no repository to resolve against, so the image is missing from the preview and the PDF.&lt;/p&gt;

&lt;p&gt;The fix is to turn each relative path into an absolute &lt;code&gt;raw.githubusercontent.com&lt;/code&gt; URL:&lt;br&gt;
&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight markdown"&gt;&lt;code&gt;&lt;span class="c"&gt;&amp;lt;!-- Before: relative path, only works on GitHub --&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;docs/architecture.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;&amp;lt;!-- After: absolute raw URL, works anywhere --&amp;gt;&lt;/span&gt;
&lt;span class="p"&gt;![&lt;/span&gt;&lt;span class="nv"&gt;Architecture&lt;/span&gt;&lt;span class="p"&gt;](&lt;/span&gt;&lt;span class="sx"&gt;https://raw.githubusercontent.com/OWNER/REPO/main/docs/architecture.png&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;



&lt;p&gt;The pattern is &lt;code&gt;https://raw.githubusercontent.com/OWNER/REPO/BRANCH/PATH&lt;/code&gt;. These URLs send the cross-origin headers a browser needs to embed the image, which is why they work in a browser-based converter. Replace &lt;code&gt;main&lt;/code&gt; with your default branch (or a tag, if you want the PDF to match a release). Paths that start with &lt;code&gt;./&lt;/code&gt; or &lt;code&gt;../&lt;/code&gt; work the same way once you resolve them from the README's folder.&lt;/p&gt;

&lt;p&gt;To fix every image at once, a find-and-replace in your editor does the job. Replace &lt;code&gt;](docs/&lt;/code&gt; with &lt;code&gt;](https://raw.githubusercontent.com/OWNER/REPO/main/docs/&lt;/code&gt; and adjust for each folder your README uses. Images that already use absolute &lt;code&gt;https://&lt;/code&gt; URLs don't need changing.&lt;/p&gt;

&lt;p&gt;If MDTool can't fetch an image (a broken path, a private URL, or a server that blocks cross-origin requests), the PDF shows a gray &lt;code&gt;[image: alt text]&lt;/code&gt; placeholder in its place instead of failing. Search the PDF for "[image:" to find any you missed.&lt;/p&gt;




&lt;h2&gt;
  
  
  Privacy: Why Client-Side Conversion Matters for READMEs
&lt;/h2&gt;

&lt;p&gt;Private repositories often have READMEs containing internal architecture decisions, credentials in example snippets, or unreleased feature documentation. When you use a server-side converter, that content passes through someone else's infrastructure.&lt;/p&gt;

&lt;p&gt;MDTool converts your README entirely in the browser using &lt;code&gt;pdfmake&lt;/code&gt;, which writes real, selectable text into the PDF. When you click Download, the PDF is assembled from the rendered HTML on your machine. Open the browser's Network tab while converting and you'll see zero requests carrying your Markdown content outbound. Your README stays on your device.&lt;/p&gt;




&lt;h2&gt;
  
  
  Comparing GitHub README to PDF Tools
&lt;/h2&gt;

&lt;div class="table-wrapper-paragraph"&gt;&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Tool&lt;/th&gt;
&lt;th&gt;GFM Tables&lt;/th&gt;
&lt;th&gt;Code Highlighting&lt;/th&gt;
&lt;th&gt;Mermaid&lt;/th&gt;
&lt;th&gt;No Upload&lt;/th&gt;
&lt;th&gt;Free&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;&lt;strong&gt;MDTool&lt;/strong&gt;&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Dillinger&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌ (PDF built on its server)&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;CloudConvert&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;Partial&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;❌&lt;/td&gt;
&lt;td&gt;10 conversions/day&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;markdowntopdf.com&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;✅&lt;/td&gt;
&lt;td&gt;Not stated&lt;/td&gt;
&lt;td&gt;Watermark on free downloads&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;&lt;/div&gt;

&lt;p&gt;&lt;em&gt;Competitor features checked against each tool's site and, for Dillinger, its &lt;a href="https://github.com/joemccann/dillinger" rel="noopener noreferrer"&gt;open-source code&lt;/a&gt;, as of October 2026.&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;For a deeper comparison, see our &lt;a href="https://www.mdtool.dev/blog/best-markdown-to-pdf-converter" rel="noopener noreferrer"&gt;best Markdown to PDF converters guide&lt;/a&gt;, or check the &lt;a href="https://www.mdtool.dev/markdown-cheat-sheet" rel="noopener noreferrer"&gt;full Markdown syntax cheatsheet&lt;/a&gt; for every element a README might use.&lt;/p&gt;




&lt;h2&gt;
  
  
  Frequently Asked Questions
&lt;/h2&gt;

&lt;p&gt;&lt;strong&gt;Q: How do I convert a README to PDF?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Open the README on GitHub, click Raw, copy the Markdown, paste it into a Markdown to PDF converter such as MDTool, and click Download PDF. Choose the GitHub theme if you want the PDF to look like the README on GitHub.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Why are images missing from my README PDF?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Most READMEs use relative image paths like &lt;code&gt;docs/screenshot.png&lt;/code&gt;, which only resolve on GitHub. Replace them with absolute &lt;code&gt;https://raw.githubusercontent.com/OWNER/REPO/BRANCH/PATH&lt;/code&gt; URLs before converting. Images from private repositories also need to be hosted somewhere public.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I convert a private GitHub README?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Yes. Copy the raw Markdown content and paste it into MDTool. Since conversion is client-side, your content never leaves your browser. You don't need to connect MDTool to your GitHub account.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Badges are showing as broken images in the PDF. What do I do?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;This usually means the badge URL is either rate-limited or requires authentication (common for private repositories). The simplest fix is to delete the badge row from the Markdown before converting. Alternatively, right-click the badge on GitHub, copy the image address, and replace the dynamic URL with the resolved static URL.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: My README has a very long table. Will it fit on the page?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Wide tables are the hardest element to handle in any Markdown-to-PDF workflow. MDTool lays the PDF out on A4 or Letter paper, and long words and URLs in cells are allowed to wrap. If your table has more than 5 to 6 columns, consider shortening cell content or splitting it into smaller tables before converting.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does MDTool support GitHub's custom &lt;code&gt;&amp;gt; [!NOTE]&lt;/code&gt; alert syntax?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;GitHub's alert extensions (&lt;code&gt;&amp;gt; [!NOTE]&lt;/code&gt;, &lt;code&gt;&amp;gt; [!WARNING]&lt;/code&gt;, etc.) are a recent addition that isn't yet part of the GFM spec. MDTool renders them as standard blockquotes. You'll see the content, but without the colored border and icon that GitHub adds.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Can I automate README to PDF conversion?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;MDTool is a browser-based tool designed for manual conversions; it has no CLI or API. For automated pipelines, such as generating PDFs in CI, see our guide to &lt;a href="https://www.mdtool.dev/blog/markdown-to-pdf-python-pandoc" rel="noopener noreferrer"&gt;Markdown to PDF with Python, Pandoc and Node&lt;/a&gt;. For code with syntax highlighting and Mermaid support in CI, see our guide on &lt;a href="https://www.mdtool.dev/blog/markdown-to-pdf-code-blocks" rel="noopener noreferrer"&gt;Markdown to PDF code blocks&lt;/a&gt;.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Q: Does the PDF include anchor links (internal links within the README)?&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Internal anchor links (e.g., &lt;code&gt;[See Installation](#installation)&lt;/code&gt;) are preserved as links in the PDF. Whether they work depends on the PDF viewer, and most desktop PDF viewers support internal anchor navigation.&lt;/p&gt;




&lt;p&gt;&lt;em&gt;I build &lt;a href="https://www.mdtool.dev" rel="noopener noreferrer"&gt;MDTool&lt;/a&gt;, the free browser converter used in this post. It's &lt;a href="https://github.com/usmankhan045/mdtool" rel="noopener noreferrer"&gt;open source&lt;/a&gt; (MIT). If your README breaks in it, I'd like to see it: open an issue or drop it in the comments.&lt;/em&gt;&lt;/p&gt;

</description>
      <category>github</category>
      <category>markdown</category>
      <category>productivity</category>
      <category>tutorial</category>
    </item>
    <item>
      <title>I got tired of paywalls for Markdown converters, so I built a free, 100% client-side alternative.</title>
      <dc:creator>Usman</dc:creator>
      <pubDate>Thu, 25 Jun 2026 11:51:02 +0000</pubDate>
      <link>https://dev.to/usmankhan45/i-got-tired-of-paywalls-for-markdown-converters-so-i-built-a-free-100-client-side-alternative-2dlc</link>
      <guid>https://dev.to/usmankhan45/i-got-tired-of-paywalls-for-markdown-converters-so-i-built-a-free-100-client-side-alternative-2dlc</guid>
      <description>&lt;p&gt;As a software engineer, I write almost everything in Markdown. It's fast, clean, and lives easily in Git. But sharing those documents with non-technical clients or teammates usually requires converting them into PDFs or Word documents.&lt;/p&gt;

&lt;p&gt;When I went looking for tools to handle this, I hit two major roadblocks:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;Privacy:&lt;/strong&gt; Most free online converters require you to upload your files to a backend server. For private code documentation, internal wiki pages, or client notes, that's a real security risk.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;Paywalls:&lt;/strong&gt; The tools that actually handled clean formatting or two-way conversions (especially for Word .docx files) were almost entirely gated behind monthly subscriptions.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;So I decided to build it myself.&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;&lt;a href="https://www.mdtool.dev" rel="noopener noreferrer"&gt;MDTool&lt;/a&gt;&lt;/strong&gt; is a free, browser-based Markdown conversion suite that processes everything locally on your machine. Zero server uploads. Zero sign-ups. And it's &lt;a href="https://github.com/usmankhan045/mdtool" rel="noopener noreferrer"&gt;open source on GitHub&lt;/a&gt; under the MIT license, so you can check exactly what happens to your files.&lt;/p&gt;

&lt;h2&gt;
  
  
  The 7 tools included
&lt;/h2&gt;

&lt;p&gt;Instead of making you jump between single-purpose websites, everything lives in one workspace:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.mdtool.dev/markdown-to-pdf" rel="noopener noreferrer"&gt;Markdown to PDF&lt;/a&gt;:&lt;/strong&gt; Real vector PDFs with selectable, searchable text (not a screenshot of the page). Renders Mermaid diagrams, highlights code blocks, and has 4 themes (GitHub, Academic, Minimal, Dark) on A4 or US Letter.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.mdtool.dev/markdown-to-word" rel="noopener noreferrer"&gt;Markdown to Word (.docx)&lt;/a&gt;:&lt;/strong&gt; Builds a genuine Word document rather than a renamed HTML file. Headings map to Word's built-in Heading 1-6 styles, so the navigation pane and automatic table of contents work, and tables and nested lists stay editable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.mdtool.dev/markdown-to-html" rel="noopener noreferrer"&gt;Markdown to HTML&lt;/a&gt;:&lt;/strong&gt; Clean, semantic HTML as a snippet or a full document.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.mdtool.dev/markdown-to-text" rel="noopener noreferrer"&gt;Markdown to Plain Text&lt;/a&gt;:&lt;/strong&gt; Strips the Markdown syntax while keeping paragraphs, lists and table rows readable.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.mdtool.dev/word-to-markdown" rel="noopener noreferrer"&gt;Word (.docx) to Markdown&lt;/a&gt;:&lt;/strong&gt; Drag in a Word file and get clean Markdown back, with the hidden proprietary styling stripped out.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.mdtool.dev/html-to-markdown" rel="noopener noreferrer"&gt;HTML to Markdown&lt;/a&gt;:&lt;/strong&gt; Paste raw HTML and get GitHub Flavored Markdown, handy for moving legacy web copy into docs.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;&lt;a href="https://www.mdtool.dev/markdown-table-generator" rel="noopener noreferrer"&gt;Markdown Table Generator&lt;/a&gt;:&lt;/strong&gt; A visual grid with column alignment and paste-from-Excel/Google Sheets.&lt;/li&gt;
&lt;/ul&gt;

&lt;h2&gt;
  
  
  How it works under the hood
&lt;/h2&gt;

&lt;p&gt;To keep everything 100% client-side, the app is built with Next.js and a handful of open-source libraries that run in the browser:&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;strong&gt;marked&lt;/strong&gt; parses the Markdown, with &lt;strong&gt;highlight.js&lt;/strong&gt; for code and &lt;strong&gt;Mermaid&lt;/strong&gt; for diagrams.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;pdfmake&lt;/strong&gt; lays out the PDF as real vector text, which is why the output stays selectable and searchable.&lt;/li&gt;
&lt;li&gt;The &lt;strong&gt;docx&lt;/strong&gt; library builds proper OpenXML Word files from the Markdown structure.&lt;/li&gt;
&lt;li&gt;
&lt;strong&gt;mammoth.js&lt;/strong&gt; and &lt;strong&gt;turndown&lt;/strong&gt; (with the GFM plugin) power the reverse direction, Word and HTML back to Markdown.&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;The heavy engines are only loaded when you actually convert something, so the pages stay fast, and your content never leaves your browser.&lt;/p&gt;

&lt;h2&gt;
  
  
  Try it out
&lt;/h2&gt;

&lt;p&gt;I built this toolkit to solve my own workflow problems, but I'm hoping it saves some of you a few dollars and a few security headaches.&lt;/p&gt;

&lt;p&gt;Everything is free at &lt;strong&gt;&lt;a href="https://www.mdtool.dev" rel="noopener noreferrer"&gt;mdtool.dev&lt;/a&gt;&lt;/strong&gt;, and the code is at &lt;strong&gt;&lt;a href="https://github.com/usmankhan045/mdtool" rel="noopener noreferrer"&gt;github.com/usmankhan045/mdtool&lt;/a&gt;&lt;/strong&gt;.&lt;/p&gt;

&lt;p&gt;I'd love to hear your thoughts, especially if you throw heavy nested tables or complex multi-level lists at the Word engine. What tools do you keep in your formatting toolkit?&lt;/p&gt;

</description>
      <category>showdev</category>
      <category>javascript</category>
      <category>webdev</category>
      <category>productivity</category>
    </item>
  </channel>
</rss>
