How to Pass Variables to a Partial Template in Hugo

As a developer, I want to keep my code as DRY as is feasible for the given project. In a Hugo project, that’s where the Partial templates come in.

Partials are smaller, context-aware components in your list and page templates that can be used economically to keep your templating DRY.

Partials, however, have one serious limitation, they’re cached during the build of a given page (or scope). Once a partial has been created, no outside logic can adjust what the partial returns (for the page). This makes the build very fast. But, prevents modifications to the partial if so desired. Imagine a scenario where a partial defines a DOM ID and you want to include the partial twice on the page. In that scenario you’ll end up with a duplicated id on the page.

Partials are cached for each page during the build.

Now, knowing why we can’t just define a variable and expect it to exist inside the partial, the solution makes a lot of sense. The partialCached is usually used to use a partial template that is cached outside of the current page scope. This function is usually used to optimize builds to be more performant.

partialCached allows for caching of partials that do not need to be re-rendered on every invocation.

The partialCached function can take extra parameters (unlimited) in order to vary the cache for the partial. That means that we can call the partial on a template, and call the partialCached (with a cache variant) and the partials will be rendered independently of each other.

Finally, we’ll use the Hugo .Scratch function to tie it all together.

.Scratch acts as a “scratchpad” to allow for writable page- or shortcode-scoped variables.

Using the scratchpad we can set a variable outide the template and get it inside the rendered partial.

example.html:

{{ define "content" }}
    {{ partial "page-single/contact_form.html" . }}
    <!-- ... -->
    {{ .Scratch.Set "form_id" "-2" }}
    {{ partialCached "page-single/contact_form.html" . "footer" }}
{{ end }}

page-single/contact_form.html:

<form id="submit-form{{ .Scratch.Get "form_id" }}">
    <label for="name">Name</label>
    <input type="text" value="" placeholder="name" id="name{{ .Scratch.Get "form_id" }}">
</form>

Using this strategy you can pass variables into partials and get around the built in partial caching that Hugo employs.