Understanding and Customizing Your Hugo Tag List Widget
I’ve been adding a bunch of articles lately (mostly AI related) and my list of tags is growing. I didn’t quite like the look of so many tags on the sidebar so I went on and make the needed code changes to trim it. Hope this helps someone trying to do the same thing.
The tag list is a common feature available on a lot of websites. It helps visitors navigate content quickly by topic they are interested in. This site uses Hugo so we’ll break down a typical Hugo template snippet for a tag list widget. Then, we’ll explore how to customize it to show the most popular tags at the top first and then limit the number of tags that shows.
Before we go to the code, first thing to do is create a copy of the template file from your theme and place it on your partials folder. I use the Mainroad theme and the taglist code is located in the file: partials/widgets/taglist.html.
Here’s the original code snippet we’ll be looking at:
{{- $tags := .Site.Taxonomies.tags }}
{{- if gt (len $tags) 0 }}
<div class="widget-taglist widget">
<h4 class="widget__title">{{ T "tags_title" }}</h4>
<div class="widget__content">
{{- range $name, $taxonomy := $tags }}
{{- with $.Site.GetPage (printf "/tags/%s" $name) }}
<a class="widget-taglist__link widget__link btn" href="{{ .RelPermalink }}" title="{{ .Title }}">
{{- .Title -}}{{- if .Site.Params.widgets.tags_counter }} ({{ $taxonomy.Count }}){{ end -}}
</a>
{{- end }}
{{- end }}
</div>
</div>
{{- end }}
Deconstructing the Original Code
Let’s go through this snippet line by line to understand its purpose:
{{- $tags := .Site.Taxonomies.tags }}
: This line initializes a variable$tags
with all the tags found across your entire Hugo site. The{{- ... -}}
syntax is Go template shorthand for “trim whitespace” around the output, keeping your generated HTML clean.{{- if gt (len $tags) 0 }}
: This is a conditional check.len $tags
counts the number of tags, andgt ... 0
checks if that count is greater than zero. The entire widget will only render if you actually have tags defined on your site.<div class="widget-taglist widget"> ... </div>
: These are standard HTMLdiv
elements, likely used for styling the widget.<h4 class="widget__title">{{ T "tags_title" }}</h4>
: This creates the widget title.{{ T "tags_title" }}
is a Hugo internationalization (i18n) function. It translates the key"tags_title"
into the appropriate language based on your site’s configuration (e.g., “Tags” for English, “タグ” for Japanese).{{- range $name, $taxonomy := $tags }}
: This initiates a loop that iterates over each tag in the$tags
variable. In each iteration:$name
gets the actual tag name (e.g., “web development”).$taxonomy
gets an object containing more details about that tag, including the count of associated posts.
{{- with $.Site.GetPage (printf "/tags/%s" $name) }}
: Thiswith
statement tries to retrieve the “page” object for the current tag. Hugo automatically creates a list page for each taxonomy term (e.g.,yoursite.com/tags/my-tag/
). If that page exists, the code inside thewith
block executes, and.
temporarily refers to that tag page object.<a class="widget-taglist__link widget__link btn" href="{{ .RelPermalink }}" title="{{ .Title }}"> ... </a>
: This creates the actual link for each tag.href="{{ .RelPermalink }}"
: Generates the relative URL to the tag’s list page (e.g.,/tags/my-tag/
).title="{{ .Title }}"
: Sets the link’s tooltip to the tag’s title.{{- .Title -}}
: Displays the tag’s name.{{- if .Site.Params.widgets.tags_counter }} ({{ $taxonomy.Count }}){{ end -}}
: This is an optional part. If you’ve settags_counter: true
under[params.widgets]
in your Hugo configuration (e.g.,config.toml
), it will display the number of posts associated with that tag (e.g., “Web Development (15)").
Showing Most Used Tags (Popularity Sort)
The original code above lists ALL tags alphabetically. To sort them by popularity (most used first), we need to leverage Hugo’s built-in .ByCount
method.
Here’s how to modify the code:
{{- $tags := .Site.Taxonomies.tags.ByCount }} {{/* Changed */}}
{{- if gt (len $tags) 0 }}
<div class="widget-taglist widget">
<h4 class="widget__title">{{ T "tags_title" }}</h4>
<div class="widget__content">
{{- range $tags }} {{/* Changed */}}
{{- with .Page }} {{/* Changed */}}
<a class="widget-taglist__link widget__link btn" href="{{ .RelPermalink }}" title="{{ .Title }}">
{{- .Title -}}{{- if .Site.Params.widgets.tags_counter }} ({{ .Count }}){{ end -}} {{/* Changed */}}
</a>
{{- end }}
{{- end }}
</div>
</div>
{{- end }}
What changed:
{{- $tags := .Site.Taxonomies.tags.ByCount }}
: We’ve added.ByCount
to the$tags
assignment. This automatically sorts your tags from the most used to the least used.{{- range $tags }}
: When usingByCount
, therange
function directly iterates over sorted taxonomy terms. Each item in the loop now contains the tag’sTerm
(name),Count
(number of posts), andPage
(the link to its list page). This means we no longer need the$name, $taxonomy
pair.{{- with .Page }}
: Since each item in the loop now has a.Page
object, we can directly usewith .Page
to get the context for the link details (.RelPermalink
,.Title
).({{ .Count }})
: The count is now directly accessible as.Count
on the current item in the loop.
Displaying Only the Top N Tags (e.g., Top 25)
To limit the number of tags displayed to, say, the top 25, you can combine the .ByCount
sorting with Hugo’s first
template function.
{{- $tags := .Site.Taxonomies.tags.ByCount }}
{{- if gt (len $tags) 0 }}
<div class="widget-taglist widget">
<h4 class="widget__title">{{ T "tags_title" }}</h4>
<div class="widget__content">
{{- range first 25 $tags }} {{/* Changed */}}
{{- with .Page }}
<a class="widget-taglist__link widget__link btn" href="{{ .RelPermalink }}" title="{{ .Title }}">
{{- .Title -}}{{- if .Site.Params.widgets.tags_counter }} ({{ .Count }}){{ end -}}
</a>
{{- end }}
{{- end }}
</div>
</div>
{{- end }}
The simple but powerful addition:
{{- range first 25 $tags }}
: Thefirst 25
function is applied before therange
. It takes the sorted$tags
list and returns only the first 25 items from it. Since the list is already sorted by popularity, these will be your 25 most popular tags.
This approach gives you a dynamic and user-friendly tag cloud, highlighting the most relevant topics on your site without overwhelming visitors with an endless list.
By understanding these Hugo template functions, you can easily customize how your site’s content is presented, making it more intuitive and engaging for your readers.