Using contentFor helper in Ghost Themes

Did you ever want to put a section in a partial to a far place in an inherited template? I turned out that it's possible.

Using contentFor helper in Ghost Themes
Photo by Mohammad Rahmani / Unsplash

While working on new landing page of Synaps Media, I used a lot of inline CSS code. My intention was keeping section partials self-contained, like a component. So a basic section partial was something like:

<style>
   .category-section {
      --card-padding: 24px;
   }
</style>

<section class="category-section">
  ...
</section>

This worked well. At the end I had the only styles that is really needed inside the document. With Smart Optimization built-in to Synaps Media, these styles were also minified automatically, so not worried about waste of resource. I know ideally it's better to keep styles in external CSS files, but because of the network latency, I didn't want to fined by Page Speed for this.

But another side effect was having many style tags inside body. Practically this is not a big issue as well. But I saw some warnings about this in HTML validators. If you care standards, style tag is not allowed inside body even though all modern browsers render it very well. I wanted to take my chance to pass this rule. But if I move all styles to head (or a separate file), then I would lose that some of my current achievements: I'll serve some unneeded styles for current page and I'll lose those self-contained handlebars templates.

I used to use Django Framework in the past. Django templates (jinja) also uses inheritance and you were able to inherit multiple levels of templates and fill blocks on upper level templates in extended templates. Would it be possible to have the similar in Handlebars?

I’ve learned that, at the point I’ve reached, this is possible with the help of contentFor. In my default.hbs file, I created a head block:

<head>
  ...
{{{block "head"}}}
</head>
<body>
  {{{body}}}
</body>
</html>

And in my section partial file I used contentFor to place my styles in to page's head section:

{{#contentFor "head"}}
<style>
   .category-section {
      --card-padding: 24px;
   }
</style>
{{/contentFor}}

<section class="category-section">
  ...
</section>

The good part is, contentFor works even if the block is not defined in the parent of current template. In my case, my partials are included in home.hbs file, which extends default.hbs. And surprisingly contentFor worked well.

Now I still have style definitions of sections inside the partial template, but result HTML has styles in head section. All items are checked!

Hope you will find this information helpful!