---
title: eleventy lessons
image:
src: 2026/hellebore.jpg
alt: Image unrelated to post. Close up on a pale green hellebore flower.
tags:
- reference
- software
---
recently I wrote *several* sites using [Eleventy](https://www.11ty.dev/){target="_blank" rel="external"} (4? 5?). Including, over the past few days, this one! That's right, if you're reading this, we're now running on 11ty and hosted by [heckin.technology](https://heckin.technology/){target="_blank" rel="external"}. See ya, GitHub. Won't miss ya.
I've compiled some of the things I've learned in a standalone site: [11ty Lessons](https://inherentlee.codeberg.page/lessons/){target="_blank" rel="external"}.
however, since I don't know how much I'll focus on that specific site - it is mostly a sample - I am re-publishing the most useful information here. I'll skip the intro to Markdown content. I'm also going to update them where I've learned more or to better match what's represented on this site.
this will comprise of 4 parts: [related posts](#related-posts), [featured images](#featured-images), [pagination](#pagination), and [tag image preview](#tag-image-preview). Feel free to jump ahead, as none depend on the others.
---
## related posts
by default, the [Eleventy base blog](github.com/11ty/eleventy-base-blog){target="_blank" rel="external"} comes with pagination between posts. Post 2 can take you to posts 1 and 3, etc.
while that is useful for *this* site, when building another site I wanted to see a couple randomly-suggested posts that shared 1 or more tags.
I started by referring to [this GitHub issue about related posts](https://github.com/11ty/eleventy/discussions/2534){target="_blank rel="external"}. I had to fix a few errors that arose from the suggested code.
I also wanted to make two changes:
1. I didn't want to just see posts that shared *all* tags, but rather posts that shared *any* tag
1. I wanted to randomly add a few posts instead of just getting whatever was first (with a shared tag) in the post order
### filters.js
after adjusting for those needs, I had the following in `filters.js`:
```js
eleventyConfig.addNunjucksFilter("excludeFromCollection", function (collection=[], pageUrl=this.ctx.page.url) {
return collection.filter(post => post.url !== pageUrl);
});
eleventyConfig.addFilter("filterByTags", function(collection=[], ...requiredTags) {
return collection.filter(post => {
return requiredTags.flat().some(tag => post.data.tags.includes(tag));
});
});
eleventyConfig.addFilter("randomize", function(array) {
// Create a copy of the array to avoid modifying the original
let shuffledArray = array.slice();
// Fisher-Yates shuffle algorithm
for (let i = shuffledArray.length - 1; i > 0; i--) {
const j = Math.floor(Math.random() * (i + 1));
[shuffledArray[i], shuffledArray[j]] = [shuffledArray[j], shuffledArray[i]];
}
return shuffledArray;
});
```
### post.njk
I used this in my post layout. `filterTagList` comes with the base blog by default, and removes the tags "posts" and "all." `head` also comes with the base blog. `postlist.njk` is my modified-from-the-base-blog post layout.
{% raw %}
```html
{% set relevantTags = tags | filterTagList %}
{% set postlist = collections.posts | filterByTags(relevantTags) | excludeFromCollection(page.url) | randomize | head(2) %}
{% if postlist.length %}
{% endif %}
```
{% endraw %}
and that sorts related posts.
---
## featured images
> this one's been edited from the lessons site. I've learned a bit more about 11ty images and feel more comfortable with my build now.
images in 11ty use the [Image Transform Plugin](https://www.11ty.dev/docs/plugins/image/#eleventy-transform){target="_blank" rel="external"}. I found it hard to find anything to reference while building this - a lot of sites in the template gallery are either text-heavy or not using the plugin - so I'm reproducing what I've got here for reference.
### file structure
```
content/
|--img/
| |--sample-0.jpg
| |--sample-1.jpg
| `--etc
|--posts/
| |--lesson-0-front-matter-and-urls.md
| |--lesson-1-headings-paragraphs-and-horizontal-lines.md
| `--etc
`--etc
```
### front matter
for any given post, my front matter references the image in this manner:
```
---
image:
src: sample-0.jpg
alt: moss on a fencepost
---
```
### image HTML transform
As mentioned, there's a plugin for images. If you started with the base blog, in `eleventy.config.js`, you'll probably find a chunk of code similar to this already in place:
```js
eleventyConfig.addPlugin(eleventyImageTransformPlugin, {
formats: ["auto"],
widths: [640],
failOnError: true,
htmlOptions: {
imgAttributes: {
// e.g. assigned on the HTML tag will override these values.
loading: "lazy",
decoding: "async",
}
},
sharpOptions: {
animated: true,
},
});
```
setting `formats` to "auto" helps - use whatever type of image you want, get that type out. The default settings that came with the Eleventy base blog didn't set a `width`, which I wanted (by default, images off my camera - like the hellebore featured image for this post - are almost 5k pixels wide). I also found it helpful to set `failOnError` to true for a little more feedback.
> NOTE: It sure seems like Eleventy will fail your image processing if there's no alt text. While admirable, it would be nice if I could find any documentation for this!
### passthrough copy
as I worked through this, I thought I needed a passthrough copy for a while. You don't - just let the plugin do its thing.
### templating
I needed images to show up in 3 places:
- In the lists of posts on the home page, I wanted each post to show its featured image
- In the "related posts" section on each individual post, I wanted each related post to show its featured image
- And of course, I wanted the post to show its own featured image
### home page and related posts
both of these sections use the same template, which in my setup is called `postlist.njk`. Within the relevant links, I added the following:
{% raw %}
```html
{% if post.data.image.src %}
{% else %}