Eleventy Markdown code block line highlighting made simple
Markdown Code Block Styling, Part 1
This article is part of a series on styling markdown code blocks.
This first installment covers numbering lines. The second will cover highlighting lines. The third will cover added lines, deleted lines, and focused lines, in combination with numbered and/or highlighted lines.
The second, Highlight Code Block Lines In Eleventy with Shiki Twoslash, covers line highlighting.
The third will cover styling added lines, deleted lines, and focused lines, in combination with numbered and/or highlighted lines.
There’s no way to number lines in the code block HTML generated by Eleventy’s default Markdown library, markdown-it, which turns Markdown like this
md```mdfirst linesecond```
md```mdfirst linesecond```
into HTML like this
html<pre><code class="language-md">first linesecond</code></pre>
html<pre><code class="language-md">first linesecond</code></pre>
The Prism-based first party syntax highlighting plugin, eleventy-plugin-syntaxhighlight, doesn’t pick up on Prism’s line number support. You can try to hack it by misusing Prism’s line highlighting, setting eleventy-plugin-syntaxhighlight’s undocumented alwaysWrapLineHighlights option to true, but ⚠️ there are multiple reports of that being glitchy — 11ty/eleventy-plugin-syntaxhighlight#10.
remark-shiki-twoslash, on the other hand, wraps each code block line in a div. For Eleventy v2 there’s the remark-shiki-twoslash plugin eleventy-plugin-shiki-twoslash. For Eleventy v3 you can use remark-shiki-twoslash with a small wrapper in your .eleventy.js file; see shikijs/twoslash#193 for details.
Shiki Twoslash, not to be confused with Shiki Twoslash
As of this writing, there are two Shiki Twoslashes, one under the shikijs org and one under the twoslashes org. remark-shiki-twoslash uses shikijs/twoslash.
Not just for Eleventy
There are remark-shiki-twoslash plugins for Markdown-It, Docusaurus, Eleventy, Gatsby, Hexo, and VuePress. Learn more at https://github.com/shikijs/twoslash.
This Markdown
md```mdfirst linesecond```
md```mdfirst linesecond```
becomes markup similar to this
html<pre class="shiki"><div class="language-id">markdown</div><div class="code-container"><code><div class="line">first line</div><div class="line">second</div></code></div></pre>
html<pre class="shiki"><div class="language-id">markdown</div><div class="code-container"><code><div class="line">first line</div><div class="line">second</div></code></div></pre>
A CSS counter can be used to style those .lines. Something like
csspre.shiki {counter-reset: codeblock-line;.line {counter-increment: codeblock-line;&::before {content: counter(codeblock-line);}}}
csspre.shiki {counter-reset: codeblock-line;.line {counter-increment: codeblock-line;&::before {content: counter(codeblock-line);}}}
With remark-shiki-twoslash, classes can be added to code blocks by including class attribute markup on the Markdown code block’s opening fence if a language is also specified on the opening fence.
This
md```md```md class="my-class"
md```md```md class="my-class"
renders as
html<pre class="shiki"><pre class="shiki my-class">
html<pre class="shiki"><pre class="shiki my-class">
Use that to support opting out of line numbers:
csspre.shiki {pre.shiki:not(.codeblock-no-line-numbers) {/* … */}
csspre.shiki {pre.shiki:not(.codeblock-no-line-numbers) {/* … */}
md```texthaslinenumbers```
md```texthaslinenumbers```
texthaslinenumbers
texthaslinenumbers
md```text class="codeblock-no-line-numbers"doesn'thavelinenumbers```
md```text class="codeblock-no-line-numbers"doesn'thavelinenumbers```
textdoesn'thavelinenumbers
textdoesn'thavelinenumbers
Highlight Code Block Lines In Eleventy with Shiki Twoslash
Eleventy Markdown code block line highlighting made simple
Comparing docs site builders: VuePress vs Starlight
How do these two frameworks measure up?