Markdown Snippets
The markdown that renders wrong. Nested code, line breaks, tables, and GitHub-only extras.
Nobody needs another list of # H1 and **bold**. These are the cases where
markdown renders differently from what you typed, in a README, a PR description,
a ticket, or a notes app.
Line breaks that actually break
A single newline is not a line break. Markdown joins those lines into one paragraph, which is why addresses and poetry come out as a run-on sentence.
Line one
Line two → renders as "Line one Line two"
Line one·· → two trailing spaces = a real <br>
Line two
Line one\ → a trailing backslash does the same, and is visible
Line two in a diff
Trailing spaces are invisible, and most editors strip them on save. The backslash form survives.
Code inside lists
The indentation has to match where the list item’s text starts. That’s three
spaces after 1. , two after - . Off by one and the block escapes the list,
which renumbers everything below it without any warning.
1. Install it
```bash
npm install
```
2. Run it
Same rule for paragraphs, nested lists and images inside a list item.
Nested fences
To show a fenced code block inside a fenced code block, make the outer fence longer. Four backticks wrapping three:
````markdown
```js
console.log('hi')
```
````
The same trick works inline. Wrap in double backticks to display a backtick, and add a space when the content starts or ends with one.
`` `code` `` → `code`
Numbering
Every item can be 1.. The renderer numbers them for you, which means reordering
a list doesn’t turn into a diff of every line.
1. First
1. Second
1. Third
To start at a different number, set the first one. 5. makes the list 5, 6, 7.
And a line that starts with a number and a period becomes a list whether you
wanted it or not, so escape it: 1985\. A good year.
Tables
| Command | What it does | Risk |
| :----------- | :-----------------: | ---: |
| `git status` | Shows the worktree | Low |
| `git clean` | Deletes untracked | High |
The colons in the separator row set alignment: left, centre, right. The pipes
don’t need to line up, only the separator row’s dashes are required. To put a
literal | inside a cell, escape it (\|) or wrap it in backticks. Tables can’t
contain line breaks, so use <br> if you must.
Things that get eaten
- Underscores mid-word.
snake_case_namecan render as italics in older parsers. Wrap identifiers in backticks and stop thinking about it. <and>. Anything that looks like a tag may be swallowed as HTML. Escape as<or use inline code.#without a space.#hashtagis not a heading,# Headingis.- Asterisks in text.
2 * 3 * 4can turn into italics, so escape with\*. - Emphasis inside a word.
un**bel**ievabledoesn’t work with_, only**.
GitHub-flavoured extras
Task lists, which render as real checkboxes in issues and PRs:
- [ ] Not done
- [x] Done
Collapsible sections. The blank line after </summary> is required, otherwise
the markdown inside stays as raw text:
<details>
<summary>Full stack trace</summary>
```
...long output...
```
</details>
Callouts, on GitHub and increasingly elsewhere:
> [!NOTE]
> Useful information.
> [!WARNING]
> This deletes data.
Also available: [!TIP], [!IMPORTANT], [!CAUTION].
Footnotes:
Here is a claim.[^1]
[^1]: And here is the source.
Diagrams, rendered natively on GitHub:
```mermaid
graph LR
A[Push] --> B{CI passes?}
B -->|yes| C[Merge]
B -->|no| A
```
And a diff block, for showing a change without a screenshot:
```diff
- const timeout = 5000
+ const timeout = 30_000
```
Two habits that save time
One sentence per line. Markdown joins them into a paragraph anyway, and diffs become readable, since a reworded sentence is a one-line change instead of a reflowed block.
Reference-style links, to keep long URLs out of the prose:
See the [installation guide][install] before filing a bug.
[install]: https://example.com/very/long/url/that/nobody/wants/inline