What Is Markdown?
Markdown is a lightweight plain-text format for writing structured content, created by John
Gruber in 2004 with a simple goal: a document should be readable as plain text and still
convert cleanly to HTML. Instead of writing <h1>Title</h1> you write
# Title; instead of <strong>word</strong> you write
**word**. The format caught on because it removes the markup noise from writing —
you never fight angle brackets while composing — while still producing well-formed HTML at the
end. Today Markdown is the default writing format for GitHub READMEs, package documentation,
note-taking apps, forum posts, chat clients, and most static-site generators, which is why a
reliable Markdown-to-HTML converter is a genuinely everyday tool.
Why Convert Markdown to HTML?
The conversion is needed every time Markdown content has to live somewhere that expects HTML: pasting a README's worth of notes into a CMS rich-text field, building an HTML email from a Markdown draft, embedding formatted content into a webpage that does not run a Markdown processor, publishing a blog post whose pipeline takes HTML directly, or preparing content for a documentation site that accepts pasted HTML. Rather than hand-translating every heading and list, you paste the source and take the finished markup — consistent, well-nested, and escaped. For people who write in Markdown and publish in HTML, the converter is the bridge between the two.
Supported Syntax at a Glance
| Markdown | HTML output |
|---|---|
# Heading | <h1>Heading</h1> |
**bold** and *italic* | <strong>bold</strong> and <em>italic</em> |
`code` and ~~strike~~ | <code>code</code> and <del>strike</del> |
- one - two | <ul> <li>one</li> <li>two</li> </ul> |
1. first 2. second | <ol> <li>first</li> <li>second</li> </ol> |
[text](https://example.com) | <a href="https://example.com">text</a> |
<https://example.com> | <a href="https://example.com">https://example.com</a> |
| ```js const x = 1; ``` | <pre><code class="language-js">const x = 1;</code></pre> |
| | a | b | |---|---| | <table><thead>…</thead><tbody>…</tbody></table> |
| > quoted text | <blockquote>…</blockquote> |
How the Converter Works
The conversion happens in two passes. The block pass walks the input line by line and
recognizes the document's structure — headings, fenced code blocks, tables, blockquotes, lists,
horizontal rules, and paragraphs — emitting the matching tags with correct nesting. The inline
pass then processes the text inside each block, recognizing emphasis (**bold**,
*italic*, ~~strikethrough~~), inline code, links, images, and
autolinks. Throughout, every piece of plain text is HTML-escaped before emission, which is what
makes the output safe: angle brackets, ampersands, and quotes in your source become their
escaped entities, so pasted HTML or a stray <script> renders as visible text
instead of executing. The two passes also mirror the two layers of the Markdown spec itself —
block structure and inline content — which keeps the output predictable.
Standards: CommonMark and GitHub Flavored Markdown
Markdown's original spec was famously loose, so in 2014 the community standardized the core as CommonMark — a precise grammar with conformance tests, adopted by GitHub, Reddit, and most tooling. On top of it, GitHub added a handful of extensions that make up GitHub Flavored Markdown (GFM): tables, strikethrough, autolinks, and task lists. This converter implements the CommonMark-style core — ATX headings, fenced code blocks, blockquotes, lists, emphasis, inline code, links, images — plus GFM tables and strikethrough, which covers the syntax used in the overwhelming majority of real documents. It deliberately skips the corner cases that confuse more than they help; the troubleshooting section below lists exactly what is not supported.
Worked Example: A Short Document
Paste this short document into the tool — the output should match exactly:
# Release Notes **Today** we shipped `v2.0` with: - Faster startup - A new [docs site](https://example.com) > Feedback welcome!
The expected HTML output:
<h1>Release Notes</h1> <p><strong>Today</strong> we shipped <code>v2.0</code> with:</p> <ul> <li>Faster startup</li> <li>A new <a href="https://example.com">docs site</a></li> </ul> <blockquote> <p>Feedback welcome!</p> </blockquote>
Notice the shape of the output: each block becomes one element at the correct nesting depth,
the list is a single <ul> containing <li> items, the
blockquote wraps its own paragraph, and the inline emphasis and link live inside the paragraph
text. There are no stray tags and no unescaped characters — exactly what you want to paste
into a page.
What This Converter Deliberately Doesn't Do
A few things are intentionally out of scope, and knowing them avoids surprises. Nested lists
(a list inside a list item) are not supported — flatten them or restructure. Setext headings
(a line of === or --- under a paragraph) are not implemented; use
# headings. Underscore emphasis is ignored so identifiers like
my_var and snake_case pass through untouched — use asterisks for
emphasis. Raw HTML passthrough is disabled for safety: HTML in the source is escaped and shown
as text. And link titles ([text](url "title")) are not parsed — the URL itself is
used. Each of these choices trades a rare syntax for predictability and safety, which suits a
converter that handles pasted, possibly untrusted, content.
Troubleshooting & Common Mistakes
Indented Code vs. Fenced Code
This converter recognizes fenced code blocks (```) but not four-space-indented
code. If your code block is indented, wrap it in backtick fences instead — or accept that it
will render as a paragraph.
Lists Running Together
A list ends at a blank line or a line that is not a list item. If two lists run together without a blank line between them, they merge into one — add a blank line to separate them.
Unclosed Code Fences
A fence that is never closed swallows the rest of the document into the code block. Always close what you open — the converter treats the end of input as the closing fence, so an unclosed fence is a silent bug rather than an error.
Underscore Italics Not Working
_text_ is not treated as emphasis. Use *text* for italics — the
underscore rule exists to protect identifiers and is unlikely to change.