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.
In this guide
- What Markdown is and why it converts to HTML
- Markdown flavors and why output differs
- Markdown to HTML reference table
- Worked examples: input and output
- Three ways to convert Markdown to HTML
- Raw HTML inside Markdown
- Security: sanitize untrusted Markdown
- Escaping special characters
- Line breaks and paragraphs
- Nested lists and indentation pitfalls
- Styling the HTML with CSS
- Front matter
- Converting HTML back to Markdown
- Accessibility of the generated HTML
- Common problems and fixes
- Best practices
- FAQ
- Bottom line
- Sources
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.
| Element | Markdown | HTML 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 |  | <img src="/img.png" alt="alt" /> |
| Bullet list | - item (also * or +) | <ul><li>item</li></ul> |
| Ordered list | 1. item | <ol><li>item</li></ol> |
| Block quote | > quote | <blockquote><p>quote</p></blockquote> |
| Inline code | `code` | <code>code</code> |
| Code block | Lines between ``` fences, or indented four spaces | <pre><code>...</code></pre> |
| Horizontal rule | ---, *** or ___ | <hr /> |
| Hard line break | Two 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 < b</code> to compare.</p>
<pre><code class="language-js">const ok = 1 < 2 && 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

> 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<:title,textarea,style,xmp,iframe,noembed,noframes,scriptandplaintext.
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:
- Sanitize the HTML output with a maintained sanitizer that allows only known tags and attributes. OWASP recommends DOMPurify for HTML sanitization.
- Sanitize last. OWASP warns that modifying content after sanitizing can void your security efforts.
- Keep the sanitizer patched. Bypasses are discovered regularly.
- Restrict link schemes to
http,httpsandmailto. - Add a Content Security Policy as defense in depth.
- 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&T and 5 < 6</p>
- You do not need to escape
&and<in normal text. The converter turns them into&and<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
startattribute 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
altattribute. Describe informative images briefly. For purely decorative images, the W3C guidance is an emptyalt, which is whatproduces. - Link text. Write
[installation guide](/install), not[here](/install). - Do not fake structure. Bold text is not a heading.
Common problems and fixes
| Problem | Cause | Fix |
|---|---|---|
| Table shows as text with pipes | Converter follows core CommonMark, no table extension | Use a GFM-capable converter or enable the table extension |
| Line breaks disappear | Single line breaks are soft breaks | Blank line for a paragraph; backslash or two spaces for a break |
| Nested list is flat or split | Nested items not indented to the parent's text | Indent to align with the parent item's first text character |
| Text turned into a code block | Indented four or more spaces | Remove the extra indentation |
| A line of text became a heading | A line of --- or === directly under it (setext heading) | Add a blank line before the dashes |
| Front matter appears in output | Converter does not support front matter | Strip it first or use a tool that reads it |
#Heading stays plain text | CommonMark needs a space after the # characters | Write # Heading |
Markdown inside a <div> is not converted | Markdown is not processed inside block-level HTML | Leave blank lines around the inner Markdown, or write that part in HTML |
| Numbered list restarts at 1 | Unindented content between items ended the list | Indent 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
- Daring Fireball: Markdown Syntax Documentation
- CommonMark Spec, version 0.31.2
- GitHub Flavored Markdown Spec
- GitHub Docs: Basic writing and formatting syntax
- Pandoc User's Guide
- OWASP Cheat Sheet Series: Cross Site Scripting Prevention Cheat Sheet
- MDN Web Docs: Element.innerHTML
- Jekyll documentation: Front Matter
- W3C WAI: Headings (Page Structure tutorial)
- W3C WAI: An alt Decision Tree