Markdown converts plain text to HTML using simple syntax. It's the standard format for READMEs, documentation sites, blog content, and developer tools. This is a practical reference for the syntax, the variations, and how to convert it programmatically.
Basic syntax
Headings
# H1
## H2
### H3
#### H4
##### H5
###### H6
Emphasis
*italic* or _italic_
**bold** or __bold__
***bold italic***
~~strikethrough~~ (GFM extension)
Lists
- Unordered item
- Another item
- Nested item (2 spaces or 1 tab)
1. Ordered item
2. Second item
1. Nested ordered item
- [ ] Task list item (GFM)
- [x] Completed task (GFM)
Links and images
[Link text](https://example.com)
[Link with title](https://example.com "Hover text")
[Reference link][id]
[id]: https://example.com "Optional title"


Code
Inline: `code here`
Fenced code block:
```javascript
const x = 42;
console.log(x);
```
Indented code block (4 spaces):
const x = 42;
Blockquotes
> This is a quote
> Multi-line quote
>
> Second paragraph in quote
Horizontal rule
---
***
___
Tables (GFM)
| Column 1 | Column 2 | Column 3 |
|----------|----------|----------|
| Cell 1 | Cell 2 | Cell 3 |
| Cell 4 | Cell 5 | Cell 6 |
| Left-align | Center | Right-align |
|:-----------|:------:|------------:|
| text | text | text |
CommonMark vs GitHub Flavored Markdown
CommonMark is a standardised specification that resolves the ambiguities in the original Markdown spec. It defines exactly how edge cases should parse.
GitHub Flavored Markdown (GFM) extends CommonMark with:
- Tables
- Task lists (
- [x]) - Strikethrough (
~~text~~) - Autolinks (bare URLs become clickable)
- Fenced code blocks with syntax highlighting
Most tools that render Markdown today support GFM. When you're writing a README for GitHub, GitLab, or most documentation platforms, assume GFM support.
Converting Markdown to HTML
Browser tool: Paste Markdown into a Markdown to HTML converter for a live split-pane preview with the rendered HTML output ready to copy.
JavaScript (marked.js):
import { marked } from 'marked'; // npm install marked
const markdown = '# Hello\n\nThis is **bold** text.';
const html = marked.parse(markdown);
// → '<h1>Hello</h1>\n<p>This is <strong>bold</strong> text.</p>\n'
IMPORTANT: Sanitize HTML output before inserting into the DOM to prevent XSS:
import { marked } from 'marked';
import DOMPurify from 'dompurify'; // npm install dompurify
const html = DOMPurify.sanitize(marked.parse(userMarkdown));
document.getElementById('output').innerHTML = html;
Node.js alternatives:
-
unified+remark+rehype: composable pipeline for advanced processing -
markdown-it: fast, extensible -
micromark: low-level, CommonMark-compliant
Python (mistune):
import mistune
md = '# Hello\n\nThis is **bold** text.'
html = mistune.html(md)
# → '<h1>Hello</h1>\n<p>This is <strong>bold</strong> text.</p>\n'
Python (markdown):
import markdown
md = '# Hello\n\nThis is **bold** text.'
html = markdown.markdown(md, extensions=['tables', 'fenced_code', 'toc'])
Command line:
# pandoc (most powerful)
pandoc input.md -o output.html
# Full HTML document
pandoc input.md -s -o output.html
# With a custom template
pandoc input.md --template=my-template.html -o output.html
# Python built-in
python3 -m markdown input.md > output.html
Embedding HTML in Markdown
Standard Markdown allows inline HTML. Most parsers pass it through:
This is **Markdown** with <span style="color:red">HTML</span> inline.
<div class="custom">
Custom HTML block
</div>
Note: Some Markdown processors sanitize or strip HTML for security — GitHub strips potentially dangerous HTML in READMEs but passes through safe elements.
Markdown in React
react-markdown is the standard choice — it renders Markdown safely without using dangerouslySetInnerHTML:
npm install react-markdown
import ReactMarkdown from 'react-markdown';
function Article({ content }) {
return <ReactMarkdown>{content}</ReactMarkdown>;
}
For GitHub Flavored Markdown (tables, strikethrough, task lists):
npm install react-markdown remark-gfm
import ReactMarkdown from 'react-markdown';
import remarkGfm from 'remark-gfm';
function Article({ content }) {
return (
<ReactMarkdown remarkPlugins={[remarkGfm]}>
{content}
</ReactMarkdown>
);
}
MDX: Markdown with JSX
MDX allows React components inside Markdown:
import Alert from './Alert'
# My Document
<Alert type="warning">This is a React component in Markdown.</Alert>
Standard **Markdown** continues here.
Used in documentation sites (Docusaurus, Nextra, Astro). The file compiles to a React component at build time.
Common issues
Paragraph spacing: Markdown requires a blank line between paragraphs. A single line break is treated as a space within the same paragraph.
This is paragraph one.
This is paragraph two. (blank line above creates a new <p>)
First sentence.
Second sentence on a new line — still the same paragraph.
Escaping special characters:
\*not italic\*
\# not a heading
\| not a table cell
Links with special characters:
[Text](https://example.com/path?key=value&other=true)
<!-- The & in the URL works in most parsers. In HTML attributes it should be & -->
Markdown to HTML conversion is a solved problem — the tools are mature and reliable. The main decision is which flavor to use (CommonMark vs GFM) and whether to sanitize user-generated Markdown before rendering it in the browser.
Top comments (0)