Markdown escape characters: backslashes and entities
Bobby Huang ·
For markdown escape characters, see the backslash sections and the entity section. The backslash sections cover the characters it works on, the places it has no effect and the places it still works. The page also covers named and numeric entity references as a second route, and how inline code can hold a backtick. Each part has a pandoc test you can repeat on your own file.
Key takeaways
- The full set of characters a backslash can escape, from the CommonMark spec, is in the section on what a backslash can escape.
- The section on where a backslash has no effect names those places, and the section on where a backslash still works names the rest.
- Entity and numeric references get their own section, covering the three forms and what they can't do.
- A numbered how-to walks through escaping one character and checking the result with pandoc.
- The section on backticks inside code spans covers inline code that has to contain a backtick.
You wanted a star in front of a word. You got an italic word instead, and the star is gone. Or a line that began with a digit and a dot turned into a list you never asked for.
This guide covers two ways to say "print this mark as text": a leading backslash, or an entity reference that spells the character out. Each one has places where it works and places where the parser ignores it. It walks through both, with the CommonMark 0.31.2 spec as the reference and pandoc 3.8.3 as the test bench.
What a backslash can escape
The spec allows a backslash escape in front of any ASCII punctuation character. That set is fixed and short. Every character on this line is escaped:
\!\"\#\$\%\&\'\(\)\*\+\,\-\.\/\:\;\<\=\>\?\@\[\\\]\^\_\`\{\|\}\~
Pandoc prints the punctuation as plain text. Each escape prefix disappears, and the escaped backslash (\\ in the input) prints once. The ampersand and the angle brackets come out as &, < and > in the HTML.
Once escaped, a character drops its Markdown role and counts as ordinary text. Each line here would start some kind of markup without its backslash:
\*Jane Doe*
\# Doe Holdings
1\. Doe Lane
\[draft](/doe)
Pandoc turns all four lines into a single paragraph. No emphasis, no heading, no list, no link. The star, the hash, the period and the brackets all print as plain characters.
Letters, digits and other characters
A backslash before anything outside that punctuation set does nothing special. It survives into the HTML as a literal backslash, and the next character prints too. The input Doe\Holdings and \3 copies comes out of pandoc as <p>Doe\Holdings and \3 copies</p>. So if you see a stray backslash on the page, check the character right after it. A letter, a digit or a non-ASCII symbol there means the backslash was never an escape.
Escaping the backslash itself
Two backslashes in a row print one backslash, and the character after them is no longer escaped. That can surprise you:
\\*Jane Doe*
Pandoc prints <p>\<em>Jane Doe</em></p>: one visible backslash, then italic text. The first backslash escaped the second, so the star went back to being a delimiter.
A backslash that ends a line is a separate topic, covered in line breaks.
How to escape a character and check it
When one character keeps turning into markup, these steps settle it.
- Name the character. Look at the rendered result and work out which mark started the markup: a star, an underscore, a hash, a bracket, a digit and dot at the head of a line.
- Confirm it's ASCII punctuation. Compare it with the line in the section above. A curly quote or other symbol from outside that set can't be escaped this way.
- Put one backslash immediately before it. No space between the backslash and the character.
- Copy the line into a scratch file, for example
test.md. - Render it. Run
pandoc -f commonmark -t html test.mdin a terminal and read the HTML. The character should appear as text, with no<em>,<h1>,<ol>or<a>around your words.
For stars and underscores in particular, the rules for when they open or close emphasis are long. The bold and italic guide goes through them, and it can save you an escape you don't need.
Where a backslash has no effect
The spec lists four places where backslash escapes don't work: code spans, code blocks, autolinks and raw HTML. In each one the backslash is kept as plain text.
`\*Jane\*`
<https://doe.example/?q=\*>
<span title="Doe\*">Jane</span>
Pandoc keeps every backslash here. The code span comes out as <code>\*Jane\*</code>. The autolink keeps the backslash in its address and in its visible text. The raw HTML tag passes through with its attribute exactly as typed. An indented or fenced code block does the same: the text inside it is printed as written, backslashes included. Block boundaries are in the code blocks guide, and tags in a Markdown file get their own raw HTML guide.
One side effect: an escape copied into a code span by mistake shows up on the page.
Where a backslash still works
Outside those four places, escapes work everywhere, including a few spots you may not expect. The spec names link destinations, link titles, link reference definitions and the info string after a code fence.
[Doe notes](/doe\*notes "Jane \*draft")
```` doe\+lang
Jane Doe
````
Pandoc builds a link with the address /doe*notes and the title Jane *draft; both backslashes are gone. The fence info string also drops its backslash, and doe+lang ends up in the code block's class.
Entity and numeric character references
The second route skips the backslash and names the character instead. CommonMark accepts three forms:
- Named: an ampersand, an HTML5 entity name, then a semicolon, such as
©. - Decimal: an ampersand, a hash, one to seven digits, then a semicolon, such as
#. - Hexadecimal: the same, with an
xorXafter the hash and one to six hex digits, such as#.
© # #
© no semicolon
&MadeUpDoe;
Pandoc renders the opening line as a copyright sign and two hash marks. The second line keeps © as text, because the spec doesn't recognize a named entity without its semicolon. The third line stays as typed too, since the name isn't on the HTML5 list.
Where entities aren't recognized
An entity typed in code, whether a span or a block, stays plain text. The input `#` stays as typed: pandoc gives a code element whose text is the five characters of the entity, not a hash mark. Outside code, the spec recognizes them everywhere, including URLs, link titles and fence info strings.
What an entity can't do
An entity always stands for a plain character. It can't stand in for a character that builds structure:
*Jane Doe*
* Doe Holdings
Decimal 42 is the star. Pandoc prints both lines as paragraphs with literal stars: the first isn't italic, and the second isn't a list item. The spec names emphasis delimiters, bullet list markers and thematic breaks as places an entity can't fill. So an entity works as an escape for a star, but it can never be the star that starts emphasis.
Backticks inside code spans
Backticks are the hard case, because a backslash can't help in this spot. A code span opens with a run of backticks and closes at the following backtick run of equal length. Here is what happens with a backslash, followed by the two forms that work:
`Doe\`s file`
``Doe`s file``
`` `Jane` ``
The first line breaks. Pandoc closes the code span at the backtick after the backslash, so the code holds Doe\ and the rest spills out as plain text with a stray backtick.
The second line uses two backticks on each side. A single backtick inside can't close a two-backtick span, so the code holds the whole phrase with its backtick.
The third line handles code that starts or ends with a backtick. Put one space just inside each end. When a span's content begins and ends with a space, and isn't all spaces, the spec strips one space from each side. Pandoc's code element then holds the word with a backtick on each end and no spaces.
No backslash is needed for this, the spec says: you can always choose a backtick run whose length doesn't occur anywhere inside your code.
For quoting values inside YAML front matter, see the quoting post.
Where Sashmark fits
Sashmark is planned desktop software for reading and correcting .md files that agents revise between your reads. It is in development and has not been released. The app itself has no AI features. Slated for v1: rendered code blocks, block quotes, links and tables; in-place edits on that page, where untouched lines keep their exact bytes when you save; Live Reload that holds your reading position after an outside change; and a Changes View that marks what's new since the snapshot you last saw. The roadmap shows progress, the help pages hold how-to detail, and planned features sets out the scope.
Updates go up at sashmark.com.
Questions
- Why is a backslash visible in my rendered text?
- The subsection on letters and digits covers one cause, and the section on where a backslash has no effect covers others.
- Can an entity reference replace a backslash escape?
- The entity section, including its part on what an entity can't do, covers this question.
- How can inline code hold a backtick?
- See the section on backticks inside code spans for worked examples you can copy.