Introduction
Shortcodes make it easy to reuse the same logic or markup across your content. They help keep Markdown files readable while allowing you to insert dynamic or configurable elements when needed.
You should consider writing a shortcode when:
- You need to reuse the same component in multiple places
- You want to centralize or share data across different content files
- You need to encapsulate complex or verbose HTML
- You want to ensure consistent presentation across posts
- You need to embed third-party content (videos, tweets, code snippets, etc.)
- You want to separate content from layout and styling concerns
- You need conditional rendering based on parameters or context
- You want to provide simple, author-friendly building blocks instead of raw HTML
The Basics
To call a shortcode in your post, use its filename (without .html).
- Use
{{% %}}when the shortcode output contains Markdown that must be rendered - Use
{{< >}}when the shortcode outputs HTML only (preferred for performance)
Examples:
{{% parameters params.yaml %}}# Markdown-aware{{< parameters "params.yaml" >}}# HTML-only{{% hugo/parameters params.yaml %}}# will look for./layouts/shortcodes/hugo/parameters.html
In this posts, we already saw that we can use shortcode provided by the theme’s modules, but let’s write some customs.
Some use cases
Split code from the articles
On this blog, I often include large code blocks. Instead of embedding them directly in Markdown, itโs often cleaner to keep them next to the article - for example in a code/ or codes/ folder - and include them using a dedicated shortcode.
This approach makes the article easier to read and allows code snippets to be reused or updated independently of the content. Separating code from content keeps articles readable while letting code evolve independently. You can achieve this with a code-snippet shortcode.
Shortcode location:
./layouts/shortcodes/code-snippet.htmlContent structure example:
1content/
2โโ posts/
3 โโ my-article/
4 โโ index.md
5 โโ codes/
6 โ โโ example.conf
- The code:
1{{- $name := printf "{code/%s,codes/%s}" ($.Get 0) ($.Get 0) }}
2{{- $res := .Page.Resources.GetMatch $name }}
3
4{{- with $res }}
5 {{- /* 1. Explicit language argument */ -}}
6 {{- $lang := $.Get 1 | default "" }}
7
8 {{- /* 2. Fallback to file extension */ -}}
9 {{- if not $lang }}
10 {{- $lang = replaceRE "^.*\\." "" .Name | lower }}
11 {{- end }}
12
13 {{- /* 3. Final fallback */ -}}
14 {{- if not $lang }}
15 {{- $lang = "txt" }}
16 {{- end }}
17
18 {{- highlight .Content $lang "" }}
19{{- else }}
20 {{- warnf "code snippet not found: %s" $name }}
21{{- end }}
The usage:
{{< code-snippet example.txt ini>}}The result:
1[Test] 2Description="Some random text to demonstrate the `code-snippet` shortcode."
code do not put file with an .html extension, otherwise Hugo will try to build it.Generate a Table from a yaml
You can generate a table from a configuration file using a shortcode. This is especially useful when you need to apply custom styling or effects, or when the dataset is large.
Instead of maintaining a long Markdown table, you can store the data in a a-long-list-of-stuffs.yaml file, which is easier to read and update over time.
So let do a shortcode which:
โ Generate a valid Markdown table
โ Auto-generates headers
โ Makes URLs clickable
โ Renders Markdown / HTML when present
โ Supports YAML / JSON / TOML inputs
- The code in
./layouts/shortcodes/table-snippet.html:
1{{- $res := .Page.Resources.GetMatch (.Get 0) }}
2{{- if not $res }}
3 {{- errorf "table-snippet: file not found: %s" (.Get 0) }}
4{{- end }}
5
6{{- $data := $res | transform.Unmarshal }}
7
8{{- /* Optional column order from shortcode */ -}}
9{{- $headers := slice }}
10{{- with .Get 1 }}
11 {{- $headers = split . "," }}
12{{- end }}
13
14{{- /* Fallback: auto-detect keys if no order provided */ -}}
15{{- if eq (len $headers) 0 }}
16 {{- range $data }}
17 {{- range $k, $_ := . }}
18 {{- if not (in $headers $k) }}
19 {{- $headers = $headers | append $k }}
20 {{- end }}
21 {{- end }}
22 {{- end }}
23{{- end }}
24
25<table class="table table-bordered table-hover table-striped">
26 <thead>
27 <tr>
28 {{- range $headers }}
29 <th>{{ . }}</th>
30 {{- end }}
31 </tr>
32 </thead>
33 <tbody>
34 {{- range $data }}
35 {{- $row := . }}
36 <tr>
37 {{- range $headers }}
38 {{- $val := index $row . | default "" }}
39 <td>{{ printf "%v" $val | markdownify }}</td>
40 {{- end }}
41 </tr>
42 {{- end }}
43 </tbody>
44</table>
The usage:
{{< table-snippet list.yaml "name,description" >}}The result:
name description Element 1 A description of element 1. Element 2 A description of element 2. Element 3 A description of element 3.
NB: here I generate HTML output, so the right syntax to use it, is {{< >}}
Some ideas for future shortcodes
Here are a few additional shortcode ideas that would fit well in an IT-focused blog:
Diff viewer โ render configuration or code changes in a readable diff format
Badges โ display states such as
Active,Disabled, orDeprecatedwith custom stylesTimelines โ visualize chronological steps, migrations, or project history
Summary
Hugo shortcodes allow you to::
๐ Keeps Markdown clean and readable
๐ Makes data reusable across multiple posts
๐งฉ Separates content from presentation
๐ Makes large among of data easy to maintain
โ ๏ธ Fails loudly if the file is missing
Well-designed shortcodes turn repetitive documentation patterns into reusable, expressive building blocks.









