A year ago this month, I wrote here about my appreciation for some code by Sia Karamalegos that made it possible, even easy, to embed YouTube videos like so, and without all the usual nasty tracking:
Note: Clicking the video constitutes your consent to view it via YouTube (including cookies). To view it on the YouTube site instead, please use this link.
That code generally looked something like this1 when used with the Nunjucks templating language in the Eleventy static site generator (SSG):
{% set videoTitle = "How to make Eyeballs that Follow You Around" %}
{% set videoId = "TGe3pS5LqEw" %}
{% include "layouts/partials/lite-youtube.njk" %}
But, as I additionally noted at the time, it could be reduced to just one line in the Hugo SSG:
{{< lite-youtube videoTitle="How to make Eyeballs that Follow You Around" videoId="TGe3pS5LqEw" >}}
Then, months later, I created an Astro component that also could be called by, yes, just one line:
<LiteYT videoTitle="How to make Eyeballs that Follow You Around" videoId="TGe3pS5LqEw" />
So, from time to time, I wondered why it couldn’t be possible to reduce this to a single-line call in Eleventy, too. But I didn’t start looking in earnest until this week, at which time I ran into a subject on which I’ve spent surprisingly little time during my nerdy obsession with SSGs: Nunjucks macros.
After reading some excellent content (see the “Acknowledgements and related material” at the bottom), I can give you this quickie solution. While it involves some setup that definitely isn’t a one-liner, it allows subsequent one-line calls of macros just as if they were components in SSGs like Astro or Next.js. Please note that the main thrust of what follows came from a 2021-12-22 comment by Ted Whitehead within an Eleventy issue on GitHub, initially filed in 2019, about using Nunjucks macros within Markdown files.
One reason why this solution is so helpful is that, once you set it up as explained below, every applicable file can have one-line access to all your macros. That’s because you can put all your macros in just one file — because you define each macro separately within the file — so, once you enable the Eleventy site to “see” that file, any content file you “bless” in the procedure below will be able to grab any macro therein.
Do the config
First, in your Eleventy site’s config file (probably a top-level .eleventy.js
file), add a collection that will expose the soon-to-be-written macros file to, in this case, all your Markdown files:
eleventyConfig.addCollection("everything", (collectionApi) => {
const macroImport = `{%- import "macros/index.njk" as macro with context -%}`
let collMacros = collectionApi.getFilteredByGlob('src/**/*.md')
collMacros.forEach((item) => {
item.template.frontMatter.content = `${macroImport}\n${item.template.frontMatter.content}`
})
return collMacros
})
Create the macros file
Important: The following step assumes the presence in your project of a suitable JavaScript file from the lite-youtube-embed
repo. In the code below, it’s in the Eleventy project’s src/assets/js/
location (hence referred to as /assets/js
since, in this project, the top-level src
is the input directory) and called lite-yt-embed_0-2-0.js.
Then, in your Eleventy project’s includes
directory, add a macros
folder and, within it, an index.njk
file for holding all your macros. Here’s such a file that contains a macro version of the YouTube-embedding code:
index.njk
{%- macro liteYT(videoTitle, videoId) -%}
<script src="/assets/js/lite-yt-embed_0-2-0.js"></script>
<lite-youtube videoid="{{ videoId }}" data-bg="url('https://i.ytimg.com/vi/{{ videoId }}/hqdefault.jpg')" {% if params %} params="{{ params }}"{% endif %}>
<button type="button" class="lty-playbtn">
<span class="lyt-visually-hidden">Play video: {{ videoTitle }}</span>
</button>
</lite-youtube>
<noscript>
<p class="ctr legal tightLead"><em>[Video playback capability requires JavaScript to be enabled.]</em></p>
</noscript>
<p class="ctr legal tightLead"><strong class="red">Note</strong>: Clicking the video constitutes your consent to view it via YouTube (including cookies). To view it on the YouTube site instead, please use <a href="https://www.youtube.com/watch?v={{ videoId }}" target="_blank" rel="noopener">this link</a>, which opens in a different browser window/tab.</p>
{%- endmacro -%}
Note: The specific indenting for the lite-youtube
element, above, is on purpose. I found that, with normal indents applied to this element, the result within the Eleventy HTML after accessing the macro from within Markdown could include unexpected p
elements wrapped around the output, causing less-than-desirable appearances. On the other hand, I didn’t encounter this problem if accessing the macro from within another Nunjucks file (more about that kind of macro call further down). I’m guessing the Markdown-related SNAFU is related to how that lite-youtube
element comes out of its parent JavaScript file.
Call the macro
With all that done, we now can go into a Markdown file and turn that formerly three-line call into just one, as was our original, alligators-free intent when we first endeavored to drain the proverbial swamp:
{{ macro.liteYT("How to make Eyeballs that Follow You Around", "TGe3pS5LqEw") }}
If you define other macros in that index.njk
file, you’ll call each similarly, with macro.
followed by its name (as specified in the macro
statement within index.njk
) and then any parameters you’ve written it to accept.
But what if you want to use the macro in any Nunjucks files? Well, even if you include .njk
files in the global through a config like this:
eleventyConfig.addCollection("everything", (collectionApi) => {
const macroImport = `{%- import "macros/index.njk" as macro with context -%}`
let collMacros = collectionApi.getFilteredByGlob([
'src/**/*.md',
'src/**/*.njk',
])
collMacros.forEach((item) => {
item.template.frontMatter.content = `${macroImport}\n${item.template.frontMatter.content}`
})
return collMacros
})
. . . you’ll still have to import
it, first:
{% from 'macros/index.njk' import liteYT %}
{{ liteYT("How to make Eyeballs that Follow You Around", "TGe3pS5LqEw") }}
This is because, to quote that comment from which I borrowed the code:
Collections don’t include layouts or includes, which still require importing macros manually[.]
Note: On the other hand, if you’re using any .njk
files for content — although I can’t imagine why when Markdown is so much easier to write, but, hey . . . — this config would allow you to do one-line calls in those Nunjucks files, as in the Markdown example.
Acknowledgements and related material
- Iain Bean, “Flexible components in Eleventy with Nunjucks macros” (2020-12-04).
- Jérôme Coupé, “Modular code with Nunjucks and Eleventy” (2021-08-06).
- Paul Irish, “Lite YouTube Embed” documentation (date unknown).
- Sia Karamalegos, “Faster YouTube embeds in Eleventy” (2021-04-07).
- Trys Mudford, “Encapsulated Eleventy/Nunjucks components with macros” (2021-02-19).
- Thomas M. Semmler, “Using parameters in your Eleventy includes with Nunjucks macros” (2021-08-10).
- W. Evan Sheehan, “Includes and Macros” (2021-11-20).
- “How to use Nunjucks macro inside Markdown files?” (Eleventy issue #613, initially posted 2019-07-16).
- Nunjucks documentation.
As for the parameters,
videoTitle
is the video’s listed full title, whilevideoId
is the video’s alphanumeric identifier which follows?v=
at the end of its URL. For example, the video shown in these examples has the following URL:
https://www.youtube.com/watch?v=TGe3pS5LqEw
. . . and, thus, avideoId
of TGe3pS5LqEw. ↩︎
Latest commit (caac9a97
) for page file:
2023-04-06 at 3:24:25 PM CDT.
Page history