Markdown keyboard keys: kbd tags and spans in pandoc
Bobby Huang ·
Under Three ways to write a key, the input and three pandoc commands appear. Fragment output for the typed tags is quoted in Hand-typed kbd tags. In Bracketed spans with a kbd class, the fragment runs for the span line are compared reader by reader. For the backtick line, see Key names in a code span. A longer combo and a span with two classes get their runs in Three-key combos and an extra class. One markdown run on a list and a table is quoted in Spans in a list and a table. The added extension and its run sit in Switching bracketed_spans on for commonmark. Numbered grep steps are in Counting kbd tags with grep.
Key takeaways
- The section Hand-typed kbd tags quotes the line each reader printed for typed tags.
- Reader-by-reader output for the span line is laid out in Bracketed spans with a kbd class.
- See Key names in a code span for what the backtick line produced.
- Runs on a three-key combo and a second class are quoted in Three-key combos and an extra class.
- A grep recipe and the counts it printed are numbered in Counting kbd tags with grep.
Over these tests, pandoc 3.8.3 turned markdown keyboard keys into three shapes: a <kbd> element, a <code> element, or the source characters left untouched. Which shape you got hung on two things, how the key was typed and which reader ran.
One Mac ran each command once, under the markdown, commonmark and commonmark_x readers. What you'll read is pandoc's printed HTML, copied as it came. How a key might look on screen was never measured, so it stays out of scope.
Three ways to write a key
The test file is kbd.md, and it holds one save shortcut written three ways. The file, as cat kbd.md printed it:
Press <kbd>Ctrl</kbd>+<kbd>S</kbd> to save.
Press [Ctrl]{.kbd}+[S]{.kbd} to save.
Press `Ctrl+S` to save.
Line one wraps each key in hand-typed HTML tags. Line two relies on pandoc's bracketed_spans extension, with a .kbd class after each key name. Line three holds the whole shortcut in one code span.
Each reader got the file through its own command:
pandoc -f markdown -t html kbd.md
pandoc -f commonmark -t html kbd.md
pandoc -f commonmark_x -t html kbd.md
All three commands finished with rc 0. The output is an HTML fragment with one <p> for each of the three nonblank input lines, and the sections below take those lines one at a time.
Hand-typed kbd tags
For line one, the three readers agreed. Each run printed:
<p>Press <kbd>Ctrl</kbd>+<kbd>S</kbd> to save.</p>
Pandoc passed the tags along unchanged, and the plus sign between them stayed a bare character. In the extension lists that pandoc --list-extensions printed, +raw_html shows up for markdown at line 53, for commonmark at line 18 and for commonmark_x at line 18. That matches what the three runs did with the tags.
Hand-typed tags have a post of their own, raw HTML in Markdown, so this page goes no further with them.
Bracketed spans with a kbd class
Line two gave one result under markdown and commonmark_x and another under plain commonmark. Here is the markdown result:
<p>Press <kbd>Ctrl</kbd>+<kbd>S</kbd> to save.</p>
From commonmark_x came that same line, character for character. So for this input, markdown and commonmark_x each turned a span carrying .kbd into a <kbd> element, and neither one wrote a <span> tag for it.
Switching to plain commonmark produced:
<p>Press [Ctrl]{.kbd}+[S]{.kbd} to save.</p>
That plain commonmark output kept the square brackets, the curly braces and the class names as ordinary paragraph text.
Each reader's extension list agrees with this result. In the markdown list, line 10 reads +bracketed_spans. The commonmark_x list has +bracketed_spans at line 5. The plain commonmark list has -bracketed_spans at line 5, a minus sign that marks it as off by default for that reader.
Between the three runs of this line, the input bytes stayed fixed and the -f value was the one thing that changed. That single swap moved the result from <kbd> elements under markdown and commonmark_x to bracket text under plain commonmark.
Key names in a code span
Line three gave one result under markdown, commonmark and commonmark_x alike:
<p>Press <code>Ctrl+S</code> to save.</p>
The whole shortcut, plus sign included, sat inside a single <code> element. No <kbd> element came from the backtick line under any of the three readers in this test. If your goal is key markup in the HTML, the code span route did not produce it in these runs.
Three-key combos and an extra class
An extra script tried two more inputs. Both files sit in the test folder next to kbd.md, and each one went through markdown, commonmark and commonmark_x in turn. The file kbd-combo.md holds a three-key shortcut:
Open the palette with [Ctrl]{.kbd}+[Shift]{.kbd}+[P]{.kbd} now.
Under markdown, pandoc printed:
<p>Open the palette with <kbd>Ctrl</kbd>+<kbd>Shift</kbd>+<kbd>P</kbd>
now.</p>
Pandoc wrapped that output onto a second line before the word now., and the commonmark_x run printed both lines exactly the same way. From plain commonmark, the line came back as text: <p>Open the palette with [Ctrl]{.kbd}+[Shift]{.kbd}+[P]{.kbd} now.</p>. With three spans, markdown and commonmark_x gave each key a separate <kbd>, just as they did with two.
The second file, kbd-twoclass.md, gives one span a pair of classes:
Press [Esc]{.kbd .key} to close.
Here is what markdown returned:
<p>Press <kbd class="key">Esc</kbd> to close.</p>
Under markdown, the kbd class turned into the element name, and key was kept as a class attribute on that element. The commonmark_x reader printed that identical line. Plain commonmark left the span as the text [Esc]{.kbd .key}. The six runs for these two files all returned rc 0.
Spans in a list and a table
The same extra script checked spans inside block structures under markdown alone. The input kbd-list.md reads:
- Save with [Ctrl]{.kbd}+[S]{.kbd}.
- Undo with [Ctrl]{.kbd}+[Z]{.kbd}.
| Action | Keys |
|---|---|
| Find | [Ctrl]{.kbd}+[F]{.kbd} |
This command converted it:
pandoc -f markdown -t html kbd-list.md
Pandoc printed:
<ul>
<li>Save with <kbd>Ctrl</kbd>+<kbd>S</kbd>.</li>
<li>Undo with <kbd>Ctrl</kbd>+<kbd>Z</kbd>.</li>
</ul>
<table>
<thead>
<tr>
<th>Action</th>
<th>Keys</th>
</tr>
</thead>
<tbody>
<tr>
<td>Find</td>
<td><kbd>Ctrl</kbd>+<kbd>F</kbd></td>
</tr>
</tbody>
</table>
Under markdown, both list items and the table cell held <kbd> elements, and rc was 0. This file was not run through the other two readers, so the page makes no claim about them for lists or tables.
Switching bracketed_spans on for commonmark
Pandoc lets you add an extension to a reader name with a +. For kbd.md, the extra script used this form:
pandoc -f commonmark+bracketed_spans -t html kbd.md
It printed:
<p>Press <kbd>Ctrl</kbd>+<kbd>S</kbd> to save.</p>
<p>Press <kbd>Ctrl</kbd>+<kbd>S</kbd> to save.</p>
<p>Press <code>Ctrl+S</code> to save.</p>
That reader name was accepted, with rc 0. Once the extension was added to commonmark, the span line became <kbd> elements, and all three output lines match the markdown run of the same file.
Counting kbd tags with grep
Each command below was issued by the extra script, with the test folder as its working directory. Replace kbd.md with your file's name to try them yourself.
cat kbd.md
pandoc -f markdown -t html kbd.md -o kbd-out-markdown.html
pandoc -f commonmark -t html kbd.md -o kbd-out-commonmark.html
pandoc -f commonmark_x -t html kbd.md -o kbd-out-commonmark_x.html
grep -c '<kbd>' kbd-out-markdown.html
grep -c '<kbd>' kbd-out-commonmark.html
grep -c '<kbd>' kbd-out-commonmark_x.html
grep -c '{.kbd}' kbd-out-commonmark.html
- Check the
catoutput and mark the lines that carry a key. - Run the three
pandoclines, which save an HTML file for each reader. Each of them is logged with rc 0. - Count lines holding
<kbd>in each file. Counts came back as2forkbd-out-markdown.html,1forkbd-out-commonmark.htmland2forkbd-out-commonmark_x.html. - Search the plain
commonmarkfile for a leftover class. That count came back1.
grep -c tallies lines that match, which means a line with two <kbd> elements still adds just one. In step 3, the gap between 2 and 1 is the span line: plain commonmark kept it as text, and step 4 found it there.
Another post from this test batch reports runs on Markdown include file lines.
Where Sashmark fits
Sashmark's design calls for correcting a slip directly within the formatted text in front of you. On saving, its Round-Trip would put down your fix while the surrounding bytes stay untouched. A separate Changes View feature, also in the plans, would mark passages an agent reworked after your previous look, git repository or not.
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.
More at sashmark.com.
Questions
- My bracketed key stayed as plain text. Why?
- Reader outputs for the span line, with the extension list lines, are compared in Bracketed spans with a kbd class.
- Does a code span give me a kbd element?
- Output for the backtick line is quoted in Key names in a code span.
- Could I get kbd elements while staying on commonmark?
- A single run using the added extension is quoted in Switching bracketed_spans on for commonmark.
- Do key spans work inside lists and tables?
- The section Spans in a list and a table quotes one markdown run on a short list and a one-row table.