What this converter understands
This is a small, purpose-built Markdown parser rather than a full CommonMark or GitHub Flavored Markdown engine. It handles a deliberately short list of constructs, and anything outside that list is passed through as plain paragraph text. Knowing the list saves you from wondering why a README renders differently here than on GitHub.
| You type | You get |
|---|---|
## Title (1 to 6 hashes) | <h2>Title</h2> |
**bold** or __bold__ | <strong> |
*em* or _em_ | <em> |
| Backtick code, and fenced blocks with an optional language | <code>, or <pre><code class="language-js"> |
[text](url "title") and  | <a href> and <img> (the title text is dropped) |
-, * or + bullets; 1. numbered lines; indented items beneath them | <ul> and <ol>, with sub-lists nested inside the parent <li> |
> quotes, and --- rules | <blockquote> and <hr> |
A pipe table: header row, a |---|:---:|---:| row, then body rows | <table> with <th> and <td> cells, aligned with text-align styles |
Worked example
The default input # Hello, a sentence with **bold**, *italic* and a code span, a two-item list and a quote produces exactly this HTML:
<h1>Hello</h1>
<p>This is <strong>bold</strong>, <em>italic</em> and <code>code</code>.</p>
<ul>
<li>one</li>
<li>two</li>
</ul>
<blockquote>A quote.</blockquote>
Nested lists
Indent a sub-item under its parent and the converter places a new list inside the parent's <li>. This input, with a numbered list under a bullet and a bullet list under that:
- fruit
1. apple
- green
- red
2. pear
- bread
produces a <ul> with two items, where the first contains an <ol> whose first item contains a second <ul>. Changing from bullets to numbers at the same indent starts a separate list instead. Item text goes through the same HTML escaping and URL filtering as the rest of the document.
A single line break inside a paragraph becomes a <br>, which matches how GitHub comments behave but not how strict CommonMark does.
What is not supported
- Task lists, footnotes and strikethrough. These come out as plain text. Simple pipe tables are supported (see above); the CSV to Markdown table tool builds the table text for you.
- List limits. Nesting is by indentation only: an item indented at least two spaces (or one tab) deeper than the item above it becomes a sub-list, and bullets and numbers can be mixed at any depth. A blank line ends the whole list, so loose lists with paragraphs inside an item are not supported, and neither are numbered lists that start from a number other than 1 or lazy continuation lines.
- Table limits. A table needs a header row and a separator row with at least one pipe. Cell text gets the same inline formatting as other text, escape a literal pipe in a cell as
\|, and a row ends at the first blank line. - Emphasis inside a word. Emphasis must start and end at a word boundary, so
snake_case_nameand2*3*4stay literal, andun*believ*ableis not italicised either. Markers inside backtick code are never converted. - Raw HTML. Any
<you type is escaped, so a pasted<script>tag is shown as text rather than kept.
Is the output safe to publish?
Text is HTML-escaped first. Quote characters in link and image URLs and in alt text are escaped too, so a crafted URL such as a"onmouseover="alert(1) stays inside its attribute instead of adding an event handler. Link and image URLs beginning with javascript: or vbscript: are replaced with #, and so are data: URLs, except data:image sources on images. That covers what this converter generates, but it is a small parser rather than a full sanitiser, so run Markdown that came from other people through one such as DOMPurify before publishing the HTML.
The converted HTML is un-minified; to shrink it for an embed, use the HTML minifier, or move it into React with HTML to JSX.