Eleventy — Using A Layout As A Partial (The Most Useful Things...)

Update 2021-02-08: This article mentions things about my website that are no longer true. The technique explained, however, still works fine.

On this website, I have both a Notes page and pages for each individual note. I wanted to use the same template for both, but I ran into an issue: accessing frontmatter data.

In Eleventy, frontmatter data for the current page is merged into the data cascade and made available on the template global scope, whereas collection items have a data property. This made it hard to write templates that work with both the page object and collection items.

Solution

[…] the most useful things are usually cloaked in an air of nonchalance, even in documentation.

YouTube user Bantu Tu, commenting on Missing Semester: Lecture 3: Editors (vim) (2020)

The solution to my problem was right there in the Eleventy docs, staring at me, its description phrased such that it couldn’t possibly be of use to anyone.

Also getCollectionItem

For completeness, a getCollectionItem filter is also included that fetches the current page from a collection.

Eleventy docs

With this filter, all my problems were solved. I prepended the following to my note.njk template (similarly for post.njk):

{%set item = note | d(collections.note | getCollectionItem(page))%}

When using note.njk as a partial, the caller assigns the variable note. When using it as a layout, no such variable will exist and the default (d()) will be used… The beauty of this configuration is that in both situations, item will be a collection item with a data property.

One caveat is that because I’m using this as a partial, I can’t use frontmatter, and therefore can’t set a layout for my layout (maybe I could use template data files…). Instead, I use Nunjucks’ builtin template inheritance.

{%if not note%}
{%extends "base.njk"%}
{%endif%}
...
{%block content%}
{%set item = note | d(collections.note | getCollectionItem(page))%}
...
{%endblock%}