table of contents feature [open]

How to Convert Markdown to HTML (with a Free Online Tool)

Illustration of Markdown text on the left being converted into HTML tags on the right

Last reviewed: October 1, 2026

Short answer: Markdown is a plain-text writing format that was designed to be converted to HTML. A converter reads your text, recognizes patterns such as # Heading, **bold** and [text](url), and writes the matching HTML elements: <h1>, <strong>, <a>. You can convert in three ways: paste into an online tool, run a command-line program such as pandoc, or call a Markdown library from your code.

Two things cause most surprises. First, there are several Markdown flavors (original Markdown, CommonMark, GitHub Flavored Markdown), so tables, task lists and footnotes work in some converters and not others. Second, Markdown allows raw HTML, so output generated from untrusted input must be sanitized before you show it in a page.

This guide shows what each piece of Markdown becomes in HTML, with input and exact output. For a quick result, paste your text into this free Markdown to HTML converter, which runs in the browser, and copy the HTML it produces. The rest of the guide helps when the output is not what you expected.

What Markdown is and why it converts to HTML

Markdown is a plain-text syntax for writing structured documents, created by John Gruber as a text-to-HTML conversion tool. Its goal, in the words of the original syntax description, is to be as easy to read and easy to write as is feasible, so that a Markdown file is publishable as plain text without looking marked up.

Markdown is not a replacement for HTML. It covers the common parts of prose: headings, paragraphs, emphasis, links, images, lists, quotes and code. Each construct maps to an HTML element. For anything else, you write HTML directly in the file.

Markdown flavors and why output differs

Different converters can produce different HTML from the same input because they implement different specifications. Knowing which flavor a tool follows explains most "it works on GitHub but not here" problems.

  • Original Markdown. Gruber's syntax description and his reference script. The CommonMark specification notes that this description does not specify the syntax unambiguously, and lists open questions such as how much a sublist must be indented and whether a blank line is needed before a block quote or heading. Implementations answered those questions differently.
  • CommonMark. A precise specification with hundreds of input/output examples, written to remove those ambiguities. Many modern converters follow it. It covers the core syntax only: no tables, no task lists, no strikethrough, no footnotes.
  • GitHub Flavored Markdown (GFM). The GFM spec describes itself as a strict superset of CommonMark. It adds tables, task list items, strikethrough, extended autolinks and a filter for certain raw HTML tags.
  • Other extended flavors. Tools such as pandoc have their own variant with extras such as footnotes and metadata blocks.

Practical rule: write core CommonMark when the text must work everywhere, and use extensions only when you know the converter at the destination supports them.

Markdown to HTML reference table

This table shows the usual HTML for each construct. The first group is core CommonMark; the second group needs GFM or another extended flavor.

ElementMarkdownHTML output
Heading# Title to ###### Title<h1> to <h6>
Emphasis*text* or _text_<em>text</em>
Strong**text** or __text__<strong>text</strong>
Link[text](/url "title")<a href="/url" title="title">text</a>
Image![alt](/img.png)<img src="/img.png" alt="alt" />
Bullet list- item (also * or +)<ul><li>item</li></ul>
Ordered list1. item<ol><li>item</li></ol>
Block quote> quote<blockquote><p>quote</p></blockquote>
Inline code`code`<code>code</code>
Code blockLines between ``` fences, or indented four spaces<pre><code>...</code></pre>
Horizontal rule---, *** or ___<hr />
Hard line breakTwo trailing spaces, or \ at line end<br />
Autolink<https://example.com><a href="https://example.com">https://example.com</a>
Extensions (GFM and others)
Table (GFM)Pipe-separated rows with a | --- | delimiter row<table> with <thead> and <tbody>
Task list (GFM)- [ ] todo and - [x] done<li> containing a disabled checkbox <input>
Strikethrough (GFM)~~text~~<del>text</del>
Extended autolink (GFM)www.example.com<a href="http://www.example.com">www.example.com</a>
Footnote (GitHub, pandoc; not in the GFM spec)Text[^1] and [^1]: Note.A superscript link plus a notes list; exact markup varies by tool

Worked examples: input and output

The outputs below follow the CommonMark and GFM specifications. Other converters may differ in small ways, such as <hr> instead of <hr />.

Example 1: heading, paragraph, emphasis, link and list

Markdown input:

# Release notes

Version **2.0** adds *faster* builds. See the
[changelog](https://example.com/changelog "Full changelog").

- Fixed login bug
- Updated docs

HTML output:

<h1>Release notes</h1>
<p>Version <strong>2.0</strong> adds <em>faster</em> builds. See the
<a href="https://example.com/changelog" title="Full changelog">changelog</a>.</p>
<ul>
<li>Fixed login bug</li>
<li>Updated docs</li>
</ul>

The line break inside the paragraph stays in the HTML source, and a browser displays it as a space. The list is "tight" (no blank lines between items), so items are not wrapped in <p> tags. With blank lines between items, each becomes <li><p>...</p></li>.

Example 2: fenced code and inline code

Markdown input:

Use `a < b` to compare.

```js
const ok = 1 < 2 && true;
```

HTML output:

<p>Use <code>a &lt; b</code> to compare.</p>
<pre><code class="language-js">const ok = 1 &lt; 2 &amp;&amp; true;
</code></pre>

The converter escapes < and & inside code for you. The word after the opening fence (the info string) becomes a language-js class on the <code> element. The converter does not color the code; syntax highlighting is a separate step.

Example 3: image, block quote and horizontal rule

![Build status chart](chart.png "Weekly builds")

> Ship small changes often.

---

HTML output:

<p><img src="chart.png" alt="Build status chart" title="Weekly builds" /></p>
<blockquote>
<p>Ship small changes often.</p>
</blockquote>
<hr />

Note that an image on its own line is still wrapped in a paragraph, because Markdown images are inline elements.

Example 4: GFM table

| Plan | Price |
| ---- | ----: |
| Free | 0     |

HTML output from a GFM converter:

<table>
<thead>
<tr>
<th>Plan</th>
<th align="right">Price</th>
</tr>
</thead>
<tbody>
<tr>
<td>Free</td>
<td align="right">0</td>
</tr>
</tbody>
</table>

A colon in the delimiter row sets alignment: :--- left, ---: right, :---: center. A plain CommonMark converter outputs the same lines as a paragraph with visible pipes.

Three ways to convert Markdown to HTML

Pick the method by volume: an online tool for one document, the command line for files and batches, a library when conversion is part of an application.

1. Online tool

Paste Markdown, copy HTML. This is the fastest route for a README section, a blog post or an email. Check which flavor the tool supports if you use tables, and do not paste confidential text into online services.

2. Command line with pandoc

Pandoc is a general document converter. The basic form from its manual names the input format, the output format and the files:

pandoc -f markdown -t html input.md -o output.html

Useful variations:

# Read the input as GitHub Flavored Markdown
pandoc -f gfm -t html input.md -o output.html

# Produce a complete page and link a stylesheet
pandoc -s --css style.css -f gfm -t html input.md -o page.html

By default pandoc writes an HTML fragment, which suits pasting into a CMS. The -s (--standalone) option produces a full document with a header and footer, and --toc adds a table of contents. -f markdown means pandoc's own extended Markdown; use -f gfm or -f commonmark to match those flavors. For files you did not write, the manual describes a --sandbox option that limits reading to the files named on the command line.

3. A library in your code

Markdown libraries fall into a few categories:

  • CommonMark-compliant parsers, often with optional GFM extensions. Choose these for predictable output.
  • Legacy parsers that follow the original Markdown behavior.
  • AST-based toolkits that parse Markdown into a syntax tree you can transform before rendering.
  • Static site generators that wrap one of the above and add templates and front matter.

Check three things in the documentation: which specification it follows, which extensions are on by default, and whether raw HTML passes through.

Raw HTML inside Markdown

Markdown lets you mix HTML into the text, and converters pass it through unchanged. Use it for things Markdown has no syntax for, such as <details> or <kbd>.

  • Block-level HTML (for example <div> or <table>) should be separated from surrounding text by blank lines. In the original Markdown rules, Markdown syntax is not processed inside block-level HTML.
  • Inline HTML (for example <span> or <kbd>) can appear inside a paragraph, and Markdown around it still works.
  • Some platforms filter HTML. The GFM spec defines a "Disallowed Raw HTML" extension that neutralizes these tags by replacing the opening < with &lt;: title, textarea, style, xmp, iframe, noembed, noframes, script and plaintext.

Use raw HTML sparingly; it may not survive if the destination sanitizes the result.

Security: sanitize untrusted Markdown

Converting Markdown does not make it safe. If the Markdown comes from users (comments, profiles, uploaded files), treat the generated HTML as untrusted and sanitize it before inserting it into a page. Otherwise you have a cross-site scripting (XSS) hole.

The reason is the raw HTML pass-through described above. The CommonMark specification defines how to parse, not how to sanitize. Input like this is valid Markdown:

Hello <img src="x" onerror="alert(1)">

[Click me](javascript:alert(1))

A converter with no safety options can emit the <img> tag as written and a link whose href uses the javascript: scheme. MDN's documentation for innerHTML uses the same kind of onerror example to show that injected markup can run script even though injected <script> elements do not execute. GFM's tag filter covers a fixed list of tags and does not remove event-handler attributes.

What to do, based on the OWASP Cross Site Scripting Prevention Cheat Sheet:

  1. Sanitize the HTML output with a maintained sanitizer that allows only known tags and attributes. OWASP recommends DOMPurify for HTML sanitization.
  2. Sanitize last. OWASP warns that modifying content after sanitizing can void your security efforts.
  3. Keep the sanitizer patched. Bypasses are discovered regularly.
  4. Restrict link schemes to http, https and mailto.
  5. Add a Content Security Policy as defense in depth.
  6. Disable raw HTML in the converter if users do not need it.

If you only convert your own documents, none of this is required.

Escaping special characters

To show a character literally instead of triggering Markdown syntax, put a backslash before it. CommonMark allows any ASCII punctuation character to be backslash-escaped.

\*not italic\*
1\. Not a list item
\# Not a heading
AT&T and 5 < 6

HTML output:

<p>*not italic*
1. Not a list item
# Not a heading
AT&amp;T and 5 &lt; 6</p>
  • You do not need to escape & and < in normal text. The converter turns them into &amp; and &lt; when they are not part of an entity or tag.
  • Backslash escapes do not work inside code spans and code blocks. Everything there is literal, which is the point of code formatting.
  • In GFM tables, write a literal pipe inside a cell as \|.

Line breaks and paragraphs

A blank line starts a new paragraph. A single line break inside a paragraph does not create a visible break; it is a "soft" break that browsers render as a space.

To force a line break (<br />) inside a paragraph, you have three options:

  • Two or more spaces at the end of the line. This is the original method. It is invisible, and some editors trim it.
  • A backslash at the end of the line. Supported by CommonMark and GFM.
  • A literal <br> tag. Works wherever raw HTML is allowed.
221B Baker Street\
London

becomes:

<p>221B Baker Street<br />
London</p>

Some platforms treat every single line break as a hard break in contexts such as comment boxes, which explains unexpected <br> tags.

Nested lists and indentation pitfalls

To nest a list or add a second paragraph to a list item, indent the nested content so it lines up with the first character of the parent item's text. That is the CommonMark rule, and GitHub's writing guide gives the same advice: place the nested marker directly below the first character of the text above it.

1. Install
   - Download the file
   - Run the installer
2. Configure
<ol>
<li>Install
<ul>
<li>Download the file</li>
<li>Run the installer</li>
</ul>
</li>
<li>Configure</li>
</ol>

The marker 1. is three characters wide, so the nested items are indented three spaces. Under a - bullet the indent is two spaces; under 10. it is four. Common mistakes:

  • Too little indent. With only two spaces under 1. , the bullets are not inside the item. They end the ordered list and start a separate one.
  • Too much indent. Text indented four or more spaces beyond where content is expected becomes a code block.
  • Numbering. The first number sets the start attribute of the <ol>; later numbers are ignored. A list written 3, 7, 9 renders as 3, 4, 5.
  • No blank line before a list. Some converters need one between a paragraph and a list.

Styling the HTML with CSS

Converted HTML has no styling of its own. The converter outputs bare elements, so the page's stylesheet decides how it looks.

The simplest approach is to wrap the output in a container and style its descendants:

.markdown-body { max-width: 70ch; line-height: 1.6; }
.markdown-body pre { overflow-x: auto; padding: 12px; background: #f6f8fa; }
.markdown-body blockquote { padding-left: 1em; border-left: 4px solid #ddd; }
.markdown-body th, .markdown-body td { border: 1px solid #ddd; padding: 6px 10px; }
.markdown-body img { max-width: 100%; height: auto; }

With pandoc, --css style.css links a stylesheet from a standalone page. If the HTML goes into an email or a CMS that strips stylesheets, you need inline style attributes, added in a post-processing step.

Front matter

Front matter is a block of metadata at the very top of a Markdown file, written in YAML between two lines of three dashes. It is not part of CommonMark or GFM; it is a convention used by static site generators and some converters.

---
title: Release notes
author: Dev Team
---

# Release notes

Jekyll's documentation requires that the front matter be the first thing in the file and be valid YAML set between triple-dashed lines. Pandoc's Markdown reads the same block as document metadata, and uses title for the page title of a standalone HTML file.

A converter that does not understand front matter treats it as content. Under CommonMark rules, the first --- becomes a horizontal rule, and the text lines followed by the closing --- become an <h2> (a setext heading). If that happens, strip the front matter before converting.

Converting HTML back to Markdown

You can convert HTML to Markdown, but the result is an approximation. Markdown can express only a subset of HTML, so anything outside that subset is either dropped or kept as raw HTML.

With pandoc, swap the formats:

pandoc -f html -t gfm page.html -o page.md

Limits to expect:

  • Classes, ids and inline styles have no core Markdown equivalent.
  • Layout markup (nested <div> elements, forms, scripts) does not map to anything.
  • Complex tables with merged cells cannot be written as GFM pipe tables.
  • The round trip is not exact. List markers, emphasis markers and line wrapping may change.

Keep the Markdown file as the source of truth and treat the HTML as generated output.

Accessibility of the generated HTML

Markdown produces clean semantic HTML only if the source is written with structure in mind.

  • Heading order. The W3C Web Accessibility Initiative advises nesting headings by rank and avoiding skipped ranks, such as an <h2> followed directly by an <h4>. In Markdown terms: do not jump from ## to #### because it looks better.
  • One page title. If the HTML will sit inside a page that already has an <h1>, start your Markdown at ##.
  • Alt text. The text in the square brackets of an image becomes the alt attribute. Describe informative images briefly. For purely decorative images, the W3C guidance is an empty alt, which is what ![](border.png) produces.
  • Link text. Write [installation guide](/install), not [here](/install).
  • Do not fake structure. Bold text is not a heading.

Common problems and fixes

ProblemCauseFix
Table shows as text with pipesConverter follows core CommonMark, no table extensionUse a GFM-capable converter or enable the table extension
Line breaks disappearSingle line breaks are soft breaksBlank line for a paragraph; backslash or two spaces for a break
Nested list is flat or splitNested items not indented to the parent's textIndent to align with the parent item's first text character
Text turned into a code blockIndented four or more spacesRemove the extra indentation
A line of text became a headingA line of --- or === directly under it (setext heading)Add a blank line before the dashes
Front matter appears in outputConverter does not support front matterStrip it first or use a tool that reads it
#Heading stays plain textCommonMark needs a space after the # charactersWrite # Heading
Markdown inside a <div> is not convertedMarkdown is not processed inside block-level HTMLLeave blank lines around the inner Markdown, or write that part in HTML
Numbered list restarts at 1Unindented content between items ended the listIndent the content under the item

Best practices

  • Pick a flavor and a converter that states which one it implements.
  • Stick to core syntax for content that must render in several places.
  • Put blank lines around headings, lists, block quotes, code fences and HTML blocks.
  • Prefer fenced code blocks with a language name.
  • Use the backslash for hard line breaks.
  • Write real alt text and keep heading levels in order.
  • Sanitize the final HTML when the Markdown comes from someone else.
  • Preview the HTML at the destination.

FAQ

How do I convert Markdown to HTML?

Paste the text into an online Markdown to HTML converter, run a command-line tool such as pandoc -f markdown -t html input.md -o output.html, or call a Markdown library from your code.

Is Markdown the same as HTML?

No. Markdown is a simpler plain-text syntax that is converted into HTML. It covers common writing elements only; anything else is written as raw HTML.

Why does my Markdown render differently on GitHub and in other tools?

They implement different flavors. GitHub Flavored Markdown adds tables, task lists, strikethrough and autolinks to CommonMark. A converter that implements only CommonMark will not recognize those.

Can I use HTML inside a Markdown file?

Yes. Raw HTML is passed through to the output, though many platforms remove some tags and attributes.

Is it safe to render user-submitted Markdown as HTML?

Only after sanitizing the generated HTML. Markdown permits raw HTML and arbitrary link destinations, so unsanitized output can carry scripts.

How do I add a line break in Markdown without starting a new paragraph?

End the line with a backslash or with two or more spaces, or insert a <br> tag.

Does Markdown support tables?

Not in the original syntax or in core CommonMark. Tables are an extension defined in GFM. For tables with merged cells, write HTML.

How do I get syntax highlighting in the converted HTML?

Add the language after the opening code fence. The converter adds a class such as language-js, which a highlighting library uses to add colors.

Can I convert HTML back to Markdown?

Yes, for content-focused HTML. Classes, styles, layout elements and complex tables are lost or left as raw HTML.

Bottom line

Markdown to HTML conversion maps a small set of text patterns to HTML elements. Most problems come from a converter whose flavor does not match your syntax, from indentation or blank lines, or from the destination's sanitizer and CSS. Write to CommonMark, add GFM features where they are supported, and sanitize output from untrusted input. For everyday conversions, a browser-based Markdown to HTML converter is the fastest route, and you can find it next to other free developer tools.

Sources referenced in this guide

Previous Post Next Post