Using inline SVG with Hugo

Posted in HTML, HUGO, GO

Using inline SVG processing for icons but also for logos may be one of the most important topics for frontend developers and designers. Even I love using Fontawesome in most of my projects, using SVG over icon sets and font libraries has some advantages not only in processing time but also in styling opportunities, width and height scaling and many more that may be necessary for your project. Saying that the reality is that many frameworks use server side processing for inline SVG editing and placing or using build pipelines with e.g. gulp prior deployment. With this the final HTML page contains the raw <svg> tags and not any <img> tags using an SVG icon.

With HUGO, the static site GO framework, we don’t have the server part and may not using gulp or any other build pipeline for placing our SVG files. But there is an easy way to overcome this issue by just using some GO manipulations and a new Hugo partial.

Create SVG Processor Partial

First we will create a separate partial to be used every time we want to place a SVG icon on the frontend.

Within your theme navigate to your partials folder and create a new file called svg.html

cd ./layouts/partials
touch svg.html

As we want to use the partial dynamically for every SVG so we need to name the SVG first

{{ $svg := .name }}

To enable custom CSS styling for our SVGs we need also to consume the required CSS class. Therefor we add another variable called $class:

{{ $class := .class }}

If you look at the raw data of an SVG file you will observe that it is always built the same way. An <svg> tag followed by several attributes, an <g> tag and at least a <path> tag drawing the SVG. This information we use to select the object where we will inject our data later. So we enhance our svg.htmlthe following to use a search pattern and select the <svg> tag but keep the content within.

{{ $oldsvg := "<svg (.*)?>((.|\n)*)</svg>" }} 

And we add another variable

{{ $newsvg := printf `<svg class="%s" ${1}>${2}</svg>` $class }}

In this variable we now inject our own CSS class into the new svgtag.

At least we will do the magic by returning the new <svg> object:

{{ return (replaceRE $oldsvg $newsvg (printf "/assets/icons/%s.svg" $svg | readFile) | safeHTML) }}

First we use printfand readFileto load the original SVG file based on the $svg that we provided earlier. In this example we look for icons sitting in the /assets/icons/folder. You may use a different one for your project.

In the second step we use the replaceREfunction to check for the $match pattern (basically the svgtag) and replace it with the §replaceWith pattern. We use safeHTML to not keep the HTML tags inside the SVG.

At last we will return the SVG object to the calling template.

Using SVG partial in Hugo templates

Having this partial we can use it in any Hugo template that we design to draw any SVG icon on site load. Just call the partial on the place you want the SVG to appear:

{{ partial "svg" (dict "name" icon-calendar "class" "icon icon-sm") }}

The special part is to call the partial with the dict parameter. This will enable us to provide variables to the partial. In this case we will provide the icon name we want to process icon-calendar and the CSS classes we want to attach (here some bootstrap classes).

If we now check our Hugo frontend with the browser inspector we observe that the partial call provides a calendar SVG icon directly processed in our HTML file:

<svg class="icon icon-sm" width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
<path d="M19 4H5C3.89543 4 3 4.89543 3 6V20C3 21.1046 3.89543 22 5 22H19C20.1046 22 21 21.1046 21 20V6C21 4.89543 20.1046 4 19 4Z" stroke="#2C3038" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M16 2V6" stroke="#2C3038" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M8 2V6" stroke="#2C3038" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
<path d="M3 10H21" stroke="#2C3038" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>

Conclusion

We can now process SVG icons directly and assign individual CSS classes during processing. The Hugo partial for SVG processing could be copy pasted and re-used in any of our projects. We just need to adjust the icon urls according to our project folder tree.

Coded with deployed with
Legal Notice