Markdown to HTML Converter

GFM + XSS sanitization, all in your browser

Why use Markdown?

Markdown is a lightweight markup language by John Gruber (2004) that converts plain text to HTML. It's used in README files on GitHub, Slack messages, Discord, Notion, Reddit, Stack Overflow. This converter supports GitHub-Flavored Markdown (GFM) — tables, fenced code blocks, task lists and auto-links. Output is sanitized with DOMPurify against XSS.

What is Markdown?

Markdown is a lightweight markup language created in 2004 by John Gruber together with Aaron Swartz. The goal: write text in plain text that is still structured and can be converted to HTML easily. Today Markdown is the de facto standard for technical documentation and is used on GitHub (READMEs, issues, pull requests), Notion, Discord, Slack, Reddit, Stack Overflow and in many static site generators (Jekyll, Hugo, Next.js, Astro).

Why write Markdown instead of HTML directly?

  • Readability: Markdown is still very readable in its raw form — no tag noise that obscures the text.
  • Speed: Faster to write — no switching between keyboard and mouse for buttons in a WYSIWYG editor.
  • Portability: A .md file opens, diffs and merges cleanly in any text editor, any Git repository and any platform.
  • Focus: You write content, not styling — separating structure from presentation keeps the focus on the text.

Markdown syntax: the most important elements

The following elements cover 90% of everyday use:

# Heading 1
## Heading 2
### Heading 3

**bold text**  *italic text*  ~~strikethrough~~

- bullet list item
- another item
  - nested item

1. ordered list item
2. second item

[Link text](https://calcsi.com)
![Image alt](https://example.com/img.png)

`inline code`

```js
// fenced code block
console.log('Hello, Markdown');
```

| Column A | Column B |
| -------- | -------- |
| cell 1   | cell 2   |
| cell 3   | cell 4   |

> A blockquote.

- [x] completed task
- [ ] open task

Markdown flavors: CommonMark, GitHub Flavored, MDX

  • CommonMark — a standardization effort started in 2014 that clarifies the ambiguous parts of Gruber's original spec. The basis for almost every modern parser today.
  • GitHub Flavored Markdown (GFM) — extends CommonMark with tables, task lists (- [ ]), strikethrough (~~text~~), auto-links and syntax highlighting for code blocks. This tool uses GFM by default.
  • MDX — combines Markdown with JSX, allowing React components inside Markdown documents. Popular in docs frameworks like Docusaurus, Next.js, Astro.

Common use cases

  • READMEs & project documentation: Every GitHub, GitLab and Bitbucket repository uses a README.md as its entry point.
  • Blog posts: Static site generators (Jekyll, Hugo, Astro, Next.js) turn Markdown files directly into finished HTML posts.
  • Notes & knowledge management: Tools like Obsidian, Logseq, Notion, Bear or Joplin store notes as Markdown — vendor-independent and future-proof.
  • Chat & forums: Discord, Slack, Reddit, Mattermost and many others support Markdown right in the input — asterisks for bold, underscores for italics.
  • Emails & newsletters: Tools like Mailchimp, ConvertKit or Ghost newsletters let you write Markdown that becomes formatted HTML email.

Frequently asked questions (FAQ)

Which Markdown standard does this tool use?

The tool uses the marked library with gfm: true and breaks: true enabled — that is GitHub Flavored Markdown on top of CommonMark. This covers nearly all GitHub-, Slack- and Notion-compatible Markdown.

Is my Markdown text sent to a server?

No. Conversion runs entirely in the browser via the marked and DOMPurify JavaScript libraries. Your text never leaves your device. You can even disconnect from the network once the page is loaded.

How do I embed images?

Use the syntax ![alt text](url). Example: ![Logo](https://example.com/logo.png). The alt text matters for accessibility and SEO. To set size or class, you can write an <img> tag directly — the converter accepts inline HTML.

Can I use HTML directly inside Markdown?

Yes. Markdown allows inline HTML, so you can use e.g. <details> for collapsible sections or <kbd> for keystrokes. Note: the result is sanitized with DOMPurify before display, removing <script>, inline event handlers and similar XSS vectors.

Are tables supported?

Yes. With GFM enabled, pipe tables are supported — columns are separated with | and the header is separated from data rows by a --- divider. Alignment is set with colons: :--- left, :---: center, ---: right.

Can I export the HTML?

Yes. Click the Copy HTML button to copy the rendered HTML to your clipboard, then paste it in an email client, CMS or code editor.

Markdown in Depth: CommonMark, GFM and Safe Rendering

Markdown was released in 2004 by John Gruber as a "text-to-HTML" writing language and has since become the lingua franca of developer documentation, README files, static site generators and chat tools. For a long time there was no formal spec, which led to dozens of incompatible parsers. CommonMark (commonmark.org) finally defined the syntax precisely in 2014: # headings, **bold**, *italic*, lists with - or 1., code with backticks, links as [text](url), blockquotes with > and inline HTML are now interpreted the same everywhere.

Beyond CommonMark, GitHub Flavored Markdown (GFM), MultiMarkdown and MDX have become widespread. GFM adds pipe tables (| A | B |), strikethrough with ~~text~~, task lists (- [ ], - [x]), autolinks and language-hinted code fences (```js). Our converter uses the marked library with { gfm: true, breaks: true } — so you get all GFM features plus hard line breaks, just like GitHub Issues and Slack render them.

Security-critical: Markdown allows embedded HTML, and a naive renderer would let an attacker inject XSS. We therefore pipe the HTML output through DOMPurify, which strips dangerous tags (<script>, <iframe>), on* event handlers and javascript: URLs before Vue's v-html renders. That way you can safely preview Markdown from untrusted sources.

How to Convert Markdown to HTML

Conversion is live — everything happens client-side, with no upload. Follow these steps:

  1. Paste your Markdown into the left field. The built-in example already demonstrates headings, lists, code blocks and links.
  2. Watch the right pane — preview updates on every keystroke. Use standard CommonMark: # for headings, - or * for lists, **bold** and *italic*.
  3. For structured content: GFM tables with | and a separator row | --- |, task lists with - [x], code fences with language hint such as ```python.
  4. Click Copy HTML to put the rendered, DOMPurify-sanitized HTML on your clipboard — ready to paste into a CMS, email template or static site.
  5. For more complex workflows: save the Markdown locally as .md, version it in Git and use the tool as a quick preview. The source stays versioned, while the HTML build happens in CI.

Real-World Examples

Here are typical Markdown inputs and their HTML results:

  • Headings: # Title turns into <h1>Title</h1>, ## Subtitle into <h2>Subtitle</h2> and so on through level 6.
  • Inline formatting: **Important** renders as <strong>Important</strong>, *emphasis* as <em>emphasis</em>, `code` as <code>code</code>.
  • GFM table: | Name | Age |\n| ---- | --- |\n| Anna | 29 | renders a full <table> with <thead> and <tbody>.
  • Code block: three backticks plus js plus code plus three backticks produces <pre><code class="language-js">...</code></pre> — ready for Highlight.js or Prism.
  • Task list: - [x] done and - [ ] open produce <input type="checkbox" checked disabled> and unchecked — perfect for issues and to-do lists.

Limits, Edge Cases and XSS Protection

Markdown is intentionally minimal — anything beyond CommonMark + GFM is non-portable. First: footnotes, definition lists and math (KaTeX) are part of neither CommonMark nor GFM; Pandoc and MultiMarkdown handle them, our converter does not. If you need math, embed $$E=mc^2$$ and have KaTeX or MathJax render it downstream. Second: frontmatter. YAML blocks at file top (---\ntitle: X\n---) belong to static site generators (Jekyll, Hugo, MkDocs), not to Markdown syntax. They would render here as heading ---. Third and critical — XSS: Markdown allows <script> tags and <a href="javascript:..."> links as inline HTML. A naive renderer would execute the payload. We filter the HTML output with DOMPurify; dangerous tags, event-handler attributes and JS URLs are removed before Vue renders. Even with that protection, never trust unknown Markdown blindly in production — some user-provided Markdown engines enable allowDangerousHtml by default, bypassing sanitization. Fourth: HTML encoding. Characters like < and > must be written as &lt;/&gt; when meant literally — otherwise Markdown reads them as HTML. Fifth: link prefetching. Browsers may prefetch http(s):// links on hover. For sensitive URLs (magic links) that is a privacy issue; use rel="noopener noreferrer" or nofollow.

More Frequently Asked Questions

Which Markdown standard does this support?
CommonMark as foundation plus GitHub Flavored Markdown (GFM). Concretely: tables, task lists, strikethrough, autolinks, language-hinted code fences and hard line breaks (breaks: true). Not supported: footnotes, MathJax/KaTeX, frontmatter, MDX/JSX.
How safe is the tool against XSS in foreign Markdown?
The HTML output is filtered through DOMPurify, which removes <script>, <iframe>, on* handlers and javascript: URLs. For production we still recommend an additional Content Security Policy (script-src 'self'), because defense in depth is always better.
How do I write code in Markdown without it being executed?
Wrap code in backticks: single for inline (`x = 1`), triple for blocks (with language hint ```js). Markdown automatically turns this into <code> elements and HTML-encodes characters like <, so the browser will not execute anything.
Why does my table not render correctly?
GFM requires the second row to be a separator | --- |, otherwise pipes are interpreted as text. Example: | Name | Age | <br> | --- | --- | <br> | Anna | 29 |. Also, every row must have the same column count.
Can I paste images directly from the clipboard?
Not directly — Markdown references images by URL, not by binary data. You can convert an image to a Data URI via our Base64 encoder and use that URI in Markdown: ![alt](data:image/png;base64,...). For larger texts a CDN is preferable.
Does my Markdown leave the browser?
No. marked and DOMPurify run as JavaScript libraries entirely client-side. No data is sent to CalcSI. Copy-to-clipboard uses the local navigator.clipboard API too.

Related tools