Add SVG icons to your Hugo site
There was a time when crafting an icon font was iconic, but now is the time to replace them with something better — something that can be easily processed, embedded and customized. Icons as they were meant to be so to say. With Hugo but without any additionally required tooling.
Let’s use SVG icons
When I developed my first Hugo theme more than four years ago (already), I was searching for a reliable option to embed SVG icons as an alternative to icon fonts, but only for the icons that the users of the theme actually needed.
I developed a partial that helped me with my task to inline SVG icons by reading-in the referenced SVG icon file, but the approach came with some disadvantages which is why I did not found it too useful:
- Sharing without caring: For quite a long time, Hugo partials (or shortcodes) were for shared in a “copy-paste & forget” blog-post fashion. I feel like every Hugo poweruser shared a shortcode once in a while which were found useful, but which readers needed to copy from a code block and therefore could not profit from future improvements.
A mechanism to reliably modularize stuff for Hugo was needed!
Luckily, this changed with Hugo 0.56 where Hugo modules were introduced, which made it possibly to ship parts that can be layered on top of your site via Hugo’s virtual FS principles.
- Missing browser support: Back then in 2017, SVG icon browser support (and their more advanced features) was not good. This forced me to fallback to an icon font approach where I needed to polyfill multiple older browsers, and things always become more messy when you have to provide all kinds of backward-compatibility. It’s not only holding you back from some good features, but especially from a good performance, and I’m a big fan of performant websites.
It’s 2021 now and a lot of things have changed in the browser landscape, be it positive or negative. One of the positive things is the great browser support for SVG icons.
- Website size: The relatively simple approach of inlining SVG icons makes it possible to only embed the icons that are wanted, but embedding one and the same icon n times leads to an increase of n times the size of the SVG icon. The same holds true for information such as SVG’s
<desc>tags which help accessibility, which is not really cool and defeats the purpose of DRY.
Luckily, the last point changed when I got to know the SVG symbol approach, which makes it possible to define a set of SVG icons ID-tagged once and invisibly somewhere on the page and then reference them across the page by using SVG’s
<use> element. This beautiful approach ensures that your page does not grow linearly per SVG icon repetition while still making individual styling possible (among other neat advantages).
Hence, I only needed to wrap up my collection of icon-related partials to package a nice and new Hugo module:
I developed the module with the goal to make it extra user-friendly and scalable, just like SVGs themselves. Here is a summary of the most important features:
- High performance with wide browser support through SVG symbol usage
- Currently supports Font Awesome, but aims to be icon-family agnostic in future
- User-friendly partial API with support for various usage patterns, including custom icon name support
- Carefully implemented and structured partials, fully utilizing Hugo’s capabilities (read more below)
- Smart and comfortable icon search function
- Auto-enabled accessibility by considering icon’s metadata
Go check it out! Set it up as a module on your Hugo site or theme within a few minutes, or continue reading for some development insights.
Implementation: A Composition of Partials
hugo-mod-icons via multiple partials which form the building blocks of the module. If you have a programming background, you can compare each partial with a function that has predefined input parameters and returns an output value. Just like in OOP, I divided the partials between the documented “public API” (e.g.
icon-partial) and more private partials (e.g.
icon-resolve) which are used internally by the public partials.
Furthermore, I decided for an architecture that makes it possible to search icons and retrieve metadata and to resolve icons independently from the icon-family. While currently only Font Awesome is supported, the plan is to add more icon families in the future!
As you can see in above figure, the user does not necessarily need to know the full icon name or where it comes from. The module automatically resolves the first found “rocket” icon even if the name is not exact.
To stabilize for future updates, the module outputs a warning in such a case as an advice to better use the full icon name (or ID) when building the site:
This greatly helps with quick prototyping. It also supports non-obvious queries such as “NASA”, where it will output the same rocket icon — by making use of Font Awesome’s metadata in the background.
Finally, if you want to see the module in action from a usage perspective, check out my Hugo theme Osprey Delight, which uses the “Data Pattern”. This usage pattern makes it possible to specify custom icon names e.g. in data/icons.yaml for a reliable way of referencing icons.
Feel free to contribute any suggestion on GitHub! Which icon family would you like to be added next?