
Last week, we set up Eleventy, a static site generator, and put it through some basic steps. I used the Warp command terminal and the Zed editor to create a nice cat-based index page. Have a quick look at that post before continuing here. Make sure you see how Eleventy picks up the minimal index.md and creates an index.html in the _site directory using the layout.html template. We will build on these in this post.
Now that we have accepted Eleventy into our life, we should make a slightly improved working environment. Where I left things last week, the “output” directory was called _site (the eleventy default name) but there was no “source” directory, so the template files were just laying around in the project root:

How we left things
Trying to work out what is doing what in web projects is bad enough, so let’s at least create a source directory so we can differentiate the templates that produce the site from the mechanics elsewhere.
It is time to start an Eleventy configuration file in the project root. I’m used to a source directory called src, and most sites keep their output in public, so let’s use that convention:
module.exports = function(eleventyConfig) { // Return your Object options: return { dir: { input: "src", output: "public" } } };
As we are changing configuration, we need to restart the server. And when we do, nothing will happen until we actually move our source material appropriately and delete the old site. That incudes _includes.
When we make the necessary file moves and run, our kitten (ok, a different kitten) returns. The directory structure, ignoring the modules directory but including the config file, now looks like this:
If you are reading this from our website, you’ll see a nice little picture of me at the end, in a round bubble. I’d like to put that on my site, to the left of the header. Reverse engineering, I can see that my image is wrapped in a “post-author-avatar” class. Like most hackers, I learn by stealing borrowing.
The trick with the little circle seems to be here:
.author-profile-photo-column img { display: block; width: 100%; aspect-ratio: 1/1; -o-object-fit: cover; object-fit: cover; border-radius: 30px }
First of all I coped my image photo-of-me.png and put the file in the new src directory. After fiddling with the JavaScript in layout.html, I got this:
.. header { background-color: #333; color: white; padding: 20px; h1 { display: inline-block; vertical-align: middle; } img { width: 5%; border-radius: 30px; display: inline-block; vertical-align: middle; float: left; } } ..
However, if you try building this it won’t work. The image will not be automatically copied to the public directory. If you made a separate style.css file too, the same is true. Eleventy knows to convert and copy what it recognises as template files, but it won’t touch other files unless you tell it to do so:
module.exports = function(eleventyConfig) { eleventyConfig.addPassthroughCopy('./src/*.css'); eleventyConfig.addPassthroughCopy('./src/*.png'); return { dir: { input: "src", output: "public" } } };
As soon as we save that, all is well:

The cat is back
And the directory looks like this:
As a reminder, the index page is produced with index.md:
--- layout: "layout.html" title: "David's Home Page" --- Hi there, I like cats!!
Now it should be pointed out that I don’t like cats that much, but I have started this theme so I am condemned to complete it. So I am going to pretend I want to add pages about famous cats.
Our steel thread is that we want to write content in Markdown, and let Eleventy take care of creating the site. While maintaining the site, we don’t want to deal with HTML.
So we’ll make a cats directory in the src, and create our first cat garfield.md into that:
--- layout: "layout.html" title: "Garfield" --- Garfield doesn't like Mondays.
If you have the server going (I have it in another Warp tab) you will see Eleventy processing it behind the scenes.
And indeed if we follow the browser path created, we see the following:

That isn’t Garfield
OK, that isn’t a picture of Garfield. Also, my nice avatar picture has disappeared from the top left. In addition, we want to link to this page from the index page.
First of all, if we want to show an image of Garfield then we’ll have to refer to it in the front matter. But first we will also need to alter the layout. So lets put the source address of our placekitten into the index.md front matter:
--- layout: "layout.html" title: "David's Home Page" catimage: "https://placekitten.com/800/400" --- Hi there, I like cats!!
And alter our layout to use the new catimage variable:
.. <body> <header> <img src="photo-of-me.png"> <h1>{{ title }}</h1> </header> <img class="cat" src="{{ catimage }}" alt="A nice cat"> {{content}} <footer> <p>© 2024 Nice Cat Page. All rights reserved.</p> </footer> </body> ..
Now, let’s add an image (from wikipedia) to our garfield.md file.
--- layout: "layout.html" title: "Garfield" catimage: "Garfieldand_friends.png" --- Garfield doesn't like Mondays.
Almost done. But it won’t work yet. Look at the directory:
My garfield image didn’t make it into the output public directory. And we know why, from our config above. So lets adjust the config file so cats go straight through too:
module.exports = function(eleventyConfig) { // Return your Object options: eleventyConfig.addPassthroughCopy('./src/*.css'); eleventyConfig.addPassthroughCopy('./src/*.png'); eleventyConfig.addPassthroughCopy('./src/cats/*.png'); return { dir: { input: "src", output: "public" } } };
Now Garfield joins the cats:
Well, actually the image is one directory below, isn’t it? So one more alteration to the Garfield file:
--- layout: "layout.html" title: "Garfield" catimage: "../Garfieldand_friends.png" --- Garfield doesn't like Mondays.
And finally we get our cat:
We’ve also, using the same logic, solved our avatar problem. It always sits in the same place ready for every page to share it, but not the same place relative to the calling page. By putting a slash in front or it, we state that we are looking for it in the root:
.. <header> <img src="/photo-of-me.png"> <h1>{{ title }}</h1> </header> ..
This should give you an idea about the little problems that occur, and where to persist when solving them. But you will note that Eleventy is quite forgiving and transparent — making errors fairly easy to fix.
OK, so we need a link to our cat from the front page. But if we were to add other cats, we would immediately have to start hacking the layout to add new links — and we don’t want to be doing that. We want to let Eleventy pick up new cats and construct the links for us.
Collections and Tags
Fortunately, Eleventy has this covered. It has the concept of a collection of pages. And we use tags in the front matter to mark a page as being part of the collection:
--- layout: "layout.html" title: "Garfield" catimage: "../Garfieldand_friends.png" tags: cats --- Garfield doesn't like Mondays.
We can then loop through our cats and make some form of index:
.. <div class="listcontainer"> <ul> {% for cat in collections.cats %} <li> <a href="/cats/{{ cat.data.title}}">{{ cat.data.title }} </a> </li> {% endfor %} </ul> </div> ..
Now we can see that Eleventy has given Liquid access to each cat’s front matter through the data method. Other than that, I’ve just made a link that assumes the filename is the same as the title. (We could improve on that).
The result, with a little help from CSS, is:

List of cats
And this gives us a link to the correct page. From now on, I should be able to add other cats in Markdown, and they will just appear in the list. Our next stop would be making a separate layout for the cats pages; there is always One More Thing to do, but that is enough for now.
So go play now and create your own site with Eleventy. You will find that you learn the usual web tricks on the way, and iterative development is not punished. Enjoy.
The post Getting up to Speed with Eleventy: Config and Collections appeared first on The New Stack.
Continuing his Eleventy tutorial, David Eastman shows how to configure the system, make use of templates, what collections are, and more.