How do I add css/js to `<head>` from partial content/template

Ah, yes. I too mentioned an issue with block in my 2nd post. I understand that you want the layout to dictate the css but push it to . I’d be interested in a way to do that too. For now my solution was to trigger it from the .md, which creates some duplication if you have more than one .md using the same template.

It seems block/define is the equivalent of compilation time parsing? They get populated regardless where you put the define? But that can’t be the case as there are multiple files defining “content” for example.

EDIT: Hold on, why do you have {{- define "customcss" }}{{ end -}} also at the end of baseof.html? You shouldn’t have any defines in baseof.html.

Your MWE isn’t producing multiple pages. Doesn’t seem like an actual MWE. You’re not calling the nifty.html partial from anywhere

I was hoping these forums would provide more help by now but perhaps it’s worth asking a question on one of the stackexchange forums.

The define in baseof.html is to supply a default. I seem to recall in one of my experiments hugo complained about a missing definition for the block. Apparently I was mistaken, so the last line of baseof.html can go.

Not yet. Even without being called the custom css is already inserted in all pages. Calling it will not change that.

If i call the partial then that page ends up empty. Every other generated page seem to get the customcss. if you comment out the partial, then that page gets generated, with the custom css.

However, both single.html and list.html layout file do define "main" so I can’t say I understand how block actually works any more … is this a bug?


In single.html you have added code outside of the definition of “main”. This is documented to generate unexpected results.

check baseof.html for a head partial, my looks like

<!DOCTYPE html>
<html {{ with site.Language.Lang }}lang="{{ . }}"{{ end }} >
{{ $section := .Section | default "home" }}
{{ partial "meta" . }}
{{ partialCached "aside" . $section }}
{{ partialCached "navigation" . $section}}
{{ block "main" . }}{{ end }}
{{ partial "footer" . }}

Your partial could be named head etc …

check this partial out under layouts/partials

something like (reduced!!)

<meta charset=utf-8 />
<meta name=viewport content="width=device-width, initial-scale=1" />
<base href={{.Site.BaseURL }} />
<title>{{ site.Title  | markdownify }} &ndash; {{ .Title  | markdownify }}</title>
{{ partialCached "favicon" . }}
{{ partialCached "css/css" . }}
{{ partialCached "js/jquery" . }}
{{ if eq .Params.Layout "gallery" }}
	{{ partialCached "css/fancybox" . }}
	{{ partialCached "js/fancybox"  . }}
{{ end }}

I used PartialCached to include all CSS files, JQUERY and fancybox, if I’m using the gallery layout.

@ju52 Thanks for the feedback. Your setup works but the inclusion of the css files is controlled by page frontmatter. What I would like to achieve is that the inclusion depends on whether a particular feature is actually used on the page.

In baseof.html or in a partial called within the <head> of baseof.html

{{- $shortCodeName := "foo" -}}
{{- $regex := printf "{{(<|%%)\\s%s\\s(>|%%)}}" $shortCodeName -}}
{{ with findRE $regex .RawContent }}
  <link rel="stylesheet" href="foo.css">
  <script src="foo.js"></script>
{{ end }}

This looks at the raw content of the page. If it finds that you’ve called a shortcode via {{< foo >}} or {{% foo %}} it will add add some CSS and JavaScript.

EDIT: This is a generic, low-level approach to parsing content. I’ve used this in the past to search for the inclusion of AMP components, specific HTML attributes, etc. To look for an individual shortcode, use .HasShortcode instead.

It is getting interesting!

This is a step forward… the inclusion if now controlled by the (raw) contents of the page. Usable in a number of situations.

The ultimate goal remains: Can I do something in the shortcode to control the inclusion?

(The answer may be ‘no’, but the question is intriguing.)

Sure. For example:


<span data-foo>{{ .Inner | .Page.RenderString }}</span>

Then, in baseof.html, use findRE against .Content instead of .RawContent to look for data-foo:

{{- $regex := "data-foo" -}}
{{ with findRE $regex .Content }}
  <link rel="stylesheet" href="foo.css">
  <script src="foo.js"></script>
{{ end }}


So the magick is: have the shortcode generate something ‘visible’ in the content, and examine the content in the base template. Nifty.

1 Like

I find this quite awkward (and prone to future portability issues) … is this the best we have? It sounds like block/define should have been the answer but their behavior still stumps me – you can have multiple defines of something and don’t get duplicate content in all pages, while other defines do push their guts in all pages. Docs aren’t very clear.

Perhaps you meant to say, “Thank you for taking the time to share what has worked for you and your team.” :grinning:


Touche. Forgot indeed to say thanks.

I, too, took time to share what worked for me, so I wasn’t a complete asshole, just a regular asshole.

1 Like

Given that the page content is fully processed before it is passed to the base html I’d expect to be able to exchange information via the page Scratch.

@jmooring and all

Thanks for this - its helpful (at least I could potentially write instructions with a shortcode to tell a user to modify the baseof.html

But is there a maybe future feature request here? to allow a shortcode to fire / hook into the head to add in scripts?

Sorry - being new maybe this is already on the roadmap?


I think that the .HasShortcode function largely addresses this requirement, in a very flexible way.


… sure - makes sense if I’m rolling my own theme … or am skilled enough to code

Equally I also don’t expect all theme developers to get on board and put a {{ if .HasShortcode}} in their theme

Oh wait … I guess I’m thinking about theme components which can extend Hugo and the main theme.

and maybe shortcodes should just have these natural limitations (like not being able to add content to the

See also Use conditional for css style with shortcode

thanks @sciurius

But would .Page.Scratch be populated when baseof.html is supposed to output ? In other words, does Hugo populate all .Content and .Page.Scratch before starting to render html in baseof.html? I didn’t find a clear explanation of the order of execution of the various components in Hugo. Looking again at @jmooring’s example above, he suggests doing a regex find on .Content to detect if some html string exists that was part of a shortcode, but shortcodes can be called in a number of places, e.g. invoked from some partial called within inside baseof.html, and all sort of other funky invocations. Are there clear docs to explain the execution path to cover all situations?