Markdown citations: keys, references and citeproc in pandoc
Bobby Huang ·
Grep counts for citation words across the spec text, with a control count, are given in the section Citation syntax in plain CommonMark. Under Citation keys in the markdown reader, pandoc's HTML for a bracketed key and a bare key is quoted from one run. Output after adding the citeproc option, including a reference list, appears in A references block with citeproc. A run on a file with no references block, and its warning, is reported under A key with no matching entry. The section Turning the citations extension off shows the same file with the extension removed. Results from the commonmark reader, with spec line numbers, fill Reading the file as commonmark. Under Check a citation with pandoc and grep, numbered steps give grep results for pandoc runs.
Key takeaways
- Counts for citation and cite from a spec grep, plus one control, sit in the section Citation syntax in plain CommonMark.
- Pandoc's HTML for both keys, with no extra option, sits in Citation keys in the markdown reader.
- Formatted text and one reference entry from a citeproc run are shown in A references block with citeproc.
- Output for two keys with the extension removed is quoted under Turning the citations extension off.
- How the commonmark reader handled the YAML lines is reported in Reading the file as commonmark.
You typed [@doe2020, p. 3] into a Markdown note to point at a source, and now you want to know what that bracket turns into. Pandoc's answer in this test changed with the reader setting and with one command-line option.
Here, one small file meets pandoc 3.8.3 (macOS build), a single reader setting at a time, and the post quotes what came back. It covers markdown citations written as keys, a YAML references: block, the --citeproc option, a key with no entry, and the commonmark reader. Commands sit beside the output they made. No viewer was tested here; the checks end at pandoc's output.
Citation syntax in plain CommonMark
No citation syntax turned up when grep searched the 0.31.2 spec text from CommonMark. With case ignored, grep found citation on 0 lines and cite on 0 lines. The stem bibliograph matched 1 line: line 5671, where the spec mentions bibliography entries while it talks about emphasis nested inside emphasis. The control term heading matched 67 lines under that same case-ignored search.
Pandoc adds the syntax through its citations extension. The command pandoc --list-extensions=markdown | grep citations printed +citations here, so the markdown reader has it switched on. Run as grep -c citations on the commonmark list, it printed 0. A control grep for attributes on that list counted 1.
Footnotes are a separate pandoc feature with their own syntax; the footnote syntax and fixes post covers them.
Citation keys in the markdown reader
The test file cite.md opens with a YAML block that lists one synthetic source, then has two cited lines:
---
references:
- id: doe2020
type: book
author:
- family: Doe
given: Jane
issued:
date-parts:
- [2020]
title: Plain Text Notes
publisher: Doe Holdings
---
As shown [@doe2020, p. 3].
@doe2020 says so.
The first cited line puts the key inside square brackets, with p. 3 after a comma. The second opens a sentence with the bare key.
With no extra option, pandoc -f markdown -t html cite.md gave:
<p>As shown <span class="citation" data-cites="doe2020">[@doe2020, p.
3]</span>.</p>
<p><span class="citation" data-cites="doe2020">@doe2020</span> says
so.</p>
Both keys became a span with the class citation and a data-cites attribute holding the key. Both spans hold the typed characters, brackets and at sign included; in the first, pandoc broke the line after p., so 3] starts a new line. The period after the closing bracket landed outside the span. The YAML block printed nothing in the body, and no reference list came out of this run.
A references block with citeproc
Adding --citeproc changed the result. pandoc -f markdown --citeproc -t html cite.md gave:
<p>As shown <span class="citation" data-cites="doe2020">(Doe 2020,
3)</span>.</p>
<p><span class="citation" data-cites="doe2020">Doe (2020)</span> says
so.</p>
<div id="refs" class="references csl-bib-body hanging-indent"
role="list">
<div id="ref-doe2020" class="csl-entry" role="listitem">
Doe, Jane. 2020. <em>Plain Text Notes</em>. Doe Holdings.
</div>
</div>
Three things changed. The bracketed key became (Doe 2020, 3): the family name, the year and the page number inside parentheses, with the p. gone. The bare key became Doe (2020), with the name outside the parentheses. And a div with the id refs appeared after the text. It holds one entry built from the YAML fields: family name, given name, year, the title inside <em>, and the publisher.
The span tags kept the same class and data-cites values as in the run without the option; the text inside them changed. The command named no style file, so this entry format is what pandoc printed by default in this test.
The YAML block in cite.md is front matter: it opens the file. For what such a block holds, see a front matter primer, and for the YAML rules inside it, YAML key rules.
A key with no matching entry
An added test, cite-noref.md, held one line and no YAML block:
As shown [@doe2020, p. 3].
The log for pandoc -f markdown --citeproc -t html cite-noref.md held a warning and then the HTML:
[WARNING] Citeproc: citation doe2020 not found
<p>As shown <span class="citation"
data-cites="doe2020">(<strong>doe2020?</strong>)</span>.</p>
The key came back in bold with a question mark after it, inside parentheses. The p. 3 from the input did not appear in this output. The run still ended with exit code 0, so the missing entry did not stop pandoc.
Without --citeproc, the same file gave the typed text inside a citation span, matching the first line from cite.md in the run without the option.
Turning the citations extension off
A minus sign and an extension name after the reader name removed that extension in this test. pandoc -f markdown-citations -t html cite.md gave the two lines below. This copy is ASCII-normalized: in the first line, pandoc wrote U+00A0 (a no-break space) between p. and 3, and the copy shows U+0020 (a plain space) in its place.
<p>As shown [@doe2020, p. 3].</p>
<p>@doe2020 says so.</p>
No span came out. The at signs stayed in both lines and the brackets stayed in the first; the second line matched the input. The first line differed from the input by that one character: the space after p. came back as U+00A0. A grep for citation on that output counted 0 lines. The YAML block printed nothing in the body here either.
Reading the file as commonmark
The commonmark reader got the same cite.md. pandoc -f commonmark -t html cite.md gave:
<hr />
<p>references:</p>
<ul>
<li>id: doe2020 type: book author:
<ul>
<li>family: Doe given: Jane issued: date-parts:
<ul>
<li>[2020] title: Plain Text Notes publisher: Doe Holdings</li>
</ul></li>
</ul></li>
</ul>
<hr />
<p>As shown [@doe2020, p. 3].</p>
<p>@doe2020 says so.</p>
The opening --- line became <hr />. Spec lines 838 to 841 say a line of three or more matching -, _ or * characters forms a thematic break. The lines that start with - became nested list items; the spec names -, + and * as bullet list markers (lines 3808 to 3809). The indented field lines were folded into the item text, as the quoted output shows. The closing --- came out as <hr /> too.
Below the second rule, the two cited lines printed as typed, with no span and no reference list.
Check a citation with pandoc and grep
When a key prints as typed, test that one line alone.
- Copy the cited line, plus its
references:block if it has one, into a new file. In this test,cat cite-noref.mdprinted the single lineAs shown [@doe2020, p. 3]. - Count citation spans.
pandoc -f markdown -t html cite.md | grep -c 'class="citation"'printed2, one for each key in the file. - Check for a reference list.
pandoc -f markdown --citeproc -t html cite.md | grep -c 'csl-entry'printed1. Dropping--citeprocfrom that command made the count0. - Read any warning line. For
cite-noref.md, which had noreferences:block, pandoc printed[WARNING] Citeproc: citation doe2020 not foundin this test. - Rule out the reader.
pandoc -f markdown-citations -t html cite.md | grep -c 'citation'printed0. Swap in the second reader and count rules:pandoc -f commonmark -t html cite.md | grep -c '<hr'printed2, one for each---line read as a rule. - If your counts differ from these, compare your output line by line with the HTML quoted for the same command above; the copy under Turning the citations extension off is ASCII-normalized.
Where Sashmark fits
Plans for Sashmark's v1 would let you edit the rendered page directly, and a clean Round-Trip, also planned, should keep each untouched line identical, byte for byte. A Changes View on the same plan, with no git needed, would highlight edits made since your previous reading. It is in development and has not been released. The app itself has no AI features. See the planned features, the help pages and the roadmap for where each part stands.
Follow the build at sashmark.com.
Questions
- Has CommonMark got citation syntax?
- Under Citation syntax in plain CommonMark, grep counts taken on the spec file appear beside a control count.
- My citation key prints as typed. Why?
- Under Turning the citations extension off, the HTML is quoted for a run with that extension removed.
- Can pandoc build a reference list from Markdown?
- Under A references block with citeproc, the citeproc run's HTML is quoted in full.
- What happens when a citation key has no entry?
- The warning and HTML from that case appear in the section A key with no matching entry.