Code block render hooks
Overview
Hugo introduced Markdown render hooks in v0.62.0. When rendering Markdown to HTML, render hooks override the conversion. Each render hook is a template, with one template for each element type: heading, image, or link.
layouts/
└── _default/
└── _markup/
├── render-heading.html
├── render-image.html
└── render-link.html
Hugo introduced render hooks for fenced code blocks in v0.93.0.
This Markdown example contains a fenced code block:
```bash {class="my-class" id="my-codeblock" lineNos=inline tabWidth=2}
declare a=1
echo "$a"
exit
```
A fenced code block consists of:
- A leading code fence
- An optional info string
- A code sample
- A trailing code fence
In the previous example, the info string contains:
- The language of the code sample (the first word)
- An optional space-delimited or comma-delimited list of attributes (everything within braces)
Attributes
The info string may contain two types of attributes:
- Generic attributes
- Highlighting options
Generic attributes
Generic attributes can be anything. In the previous example, the generic attributes are class
and id
.
In the absence of special handling within a code block render hook, Hugo adds each generic attribute to the HTML element surrounding the rendered code block.
Consistent with its content security model, Hugo removes HTML event attributes such as
onclick
andonmouseover
.
Highlighting options
Hugo uses the Chroma syntax highlighter to render the code sample. Chroma performs lexical analysis with a lexer that is unique to each code language.
You can control the appearance of the rendered code by specifying one or more highlighting options. The available options are anchorLineNos
, guessSyntax
, hl_Lines
, lineAnchors
, lineNos
, lineNoStart
, lineNumbersInTable
, noClasses
, style
, and tabWidth
.
When used in an info string, the names of the highlighting options are case-insensitive.
In the previous example, the highlighting options are lineNos
and tabWidth
.
Note that
style
is also a global HTML attribute. When specified in a code block info string,style
is a highlighting option, not an HTML attribute.
Template
Create the code block render hook in the layouts/_default/_markup
directory:
layouts/
└── _default/
└── _markup/
├── render-codeblock.html
├── render-heading.html
├── render-image.html
└── render-link.html
Context
The code block render hook receives the following context:
.Attributes
- (
map
) The generic attributes from the info string. .Inner
- (
string
) The content between the leading and trailing code fences, excluding the info string. .Options
- (
map
) The highlighting options from the info string. .Ordinal
- (
int
) The zero-based ordinal of the code block on the page. .Page
- (
page
) A reference to the page containing the code block. .Position
- (
text.Position
) The position of the code block within the page content, including the filename, line number, and column number. Intended for error reporting, this can be expensive to calculate. .Type
- (
string
) The first word of the info string.
Functions
Hugo provides three template functions related to syntax highlighting:
transform.CanHighlight TYPE
- (
bool
) Returnstrue
if the syntax highlighter has a lexer forTYPE
. transform.Highlight INNER TYPE [OPTIONS]
- (
template.HTML
) Returns highlighted code wrapped in<div>
,<pre>
, and<code>
elements. transform.HighlightCodeBlock CONTEXT [OPTIONS]
- (
highlight.HightlightResult
) Returns a structure with two methods:.Wrapped
- (
template.HTML
) Returns highlighted code wrapped in<div>
,<pre>
, and<code>
elements. This is identical to the value returned by thetransform.Highlight
function. .Inner
- (
template.HTML
) Returns highlighted code without any wrapping elements, allowing you to create your own wrapper.
Examples
These examples explain how to use context and functions within a code block render hook.
Default
This template replicates the behavior obtained when a code block render hook does not exist. We pass the entire context received by the template to the transform.HighlightCodeBlock
function without overriding any options, then display the wrapped results.
{{ $result := transform.HighlightCodeBlock . }}
{{ $result.Wrapped }}
To prevent undesirable whitespace when displayed in the browser, Hugo renders the HTML on a single line.
<div class="highlight"><pre tabindex="0" class="chroma"><code class="language-bash" data-lang="bash"><!-- highlighted code --></code></pre></div>
Custom wrapper
To customize the wrapper elements, use the .Wrapped
or .Inner
methods on thetransform.HighlightCodeBlock
result.
When using the
.Inner
method ontransform.HighlightCodeBlock
…To prevent undesirable whitespace when displayed in the browser, end each line in your template with a comment that chomps the whitespace. This syntax makes the code somewhat easier to read by allowing indentation and newlines.
This syntax is necessary due to the behavior of the
pre
element.
This example overrides default rendering, wrapping each code block in a div
element with a unique id
attribute.
{{ $id := printf "codeblock-%d" .Ordinal }}
<div id="{{ $id }}">
{{ $result := transform.HighlightCodeBlock . }}
{{ $result.Wrapped }}
</div>
Conditional behavior
This example enables line numbers if the syntax highlighter has a lexer
for the given code language (excluding plain text and Markdown) and disables line numbers for other code languages.
{{ $lineNumbers := false }}
{{ $ignoredLanguages := slice "md" "markdown" "text" "txt" }}
{{ if and (transform.CanHighlight .Type ) (not (in $ignoredLanguages .Type)) }}
{{ $lineNumbers = "inline" }}
{{ end }}
{{ $options := merge .Options (dict "linenos" $lineNumbers) }}
{{ $result := transform.HighlightCodeBlock . $options }}
{{ $result.Wrapped }}
Template per language
Although you can use one template with conditional logic to control the behavior on a per-language basis, you can also create language-specific templates.
layouts/_default/_markup/
├── render-codeblock.html
├── render-codeblock-gallery.html
├── render-codeblock-katex.html
├── render-codeblock-mermaid.html
└── render-codeblock-python.html
For example, to use a KaTex render hook to render a mathematical expression or equation:
```katex
$$
\frac{1}{\Gamma(s)}\int_{0}^{\infty}\frac{u^{s-1}}{e^{u}-1}\mathrm{d}u
$$
```
With this capability, you can use a code block render hook instead of a shortcode for mathematical expressions, diagrams, image galleries, and more.
See these articles for specific examples: