← Back to the journal

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_name can 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 &lt; or use inline code.
  • # without a space. #hashtag is not a heading, # Heading is.
  • Asterisks in text. 2 * 3 * 4 can turn into italics, so escape with \*.
  • Emphasis inside a word. un**bel**ievable doesn’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