Understanding 11ty's Collections

In the first article of my web development series, I described how to create the initial pages of a blog using 11ty. With the simple pages wrapped up, it’s time to turn up the complexity a bit. An actual blog needs an index and maybe an archive page, so in the second part of my series, I’ll focus on that and show some tips and tricks along the way.

Creating pages with a static site generator is usually pretty straightforward, and 11ty is no different. But most websites are more than just simple pages, and this is where 11ty really starts to shine. This article will continue right where the first article left off, so let’s begin by creating an index page for all the blog posts.

Creating a start page

Remember that every page in 11ty starts with a Markdown file, so let’s check out /content/blog/index.md.

---
permalink: /
layout: BlogLayout.jsx
title: Blog
---

Easy enough. Let’s look at the layout.

const Navigation = require("../components/Navigation")

function BlogLayout({ collections: { article: articles }, page, title }) {
  return (
    <>
      <Navigation url={page.url} />
      <main>
        <header>
          <h1>{title}</h1>
        </header>
        {articles.map((article) => {
          return (
            <article>
              <h2>{article.data.title}</h2>
              <p>{article.data.excerpt}</p>
              <p>
                <a href={article.url}>Read full article</a>
              </p>
            </article>
          )
        })}
      </main>
    </>
  )
}

module.exports = {
  default: BlogLayout,
  data: {
    layout: "BaseLayout.jsx"
  }
}

The layout should look familiar to you, but if you take a closer look at the function declaration, you will see something interesting.

function BlogLayout({ collections: { article: articles }, page, title }) {

Say hello to 11ty’s collections.

Collections

11ty organizes its content into something called collections. Out of the box, you get the special collection collections.all that contains a list of all pages. More interesting, though, is that 11ty also creates a collection for every tag you add to your Markdown files.

Remember that the page we added in part one included the frontmatter data tags: [article]. Therefore 11ty created an article collection that you can iterate over, just like any array in JavaScript, to create a list of links for the user.

Collections are easy to use but bring a lot of power.

Excerpts

A list of links could be more exciting, though, so blogs often show a short preview of the article right on the start page. This is called an excerpt. 11ty provides this functionality out of the box, but it needs to be enabled. All configuration is done in config/11ty.config.js. I’ve already configured this in the example project.

// Configure excerpt
config.setFrontMatterParsingOptions({
  excerpt: true,
  excerpt_alias: "excerpt"
})

This configuration will make 11ty look for the token --- in the pages, remove that from the output, and put everything before --- in the data property excerpt. Check out the file 2022-10-02-introduction.md for an example.

Looking at the loop in the layout above, you can see that we use the excerpt to create a nicer start page.

Archive pages

Listing things is an excellent use of collections, but it doesn’t end there.

Let’s say that you write a lot of articles. This means you may have to limit the number of articles you show on your start page. Where can you access the rest?

The obvious answer would be to create a separate page for your archive, use a simpler layout without an excerpt, and list all posts there. But where is the fun in that? Instead, I want to have one page for each tag so that I can see all articles for that tag, and as always, it starts in a Markdown file.

---
permalink: /archive//
layout: ArchiveLayout.jsx
title: Archive
pagination:
  data: collections
  size: 1
  alias: tag
---

Remember when I wrote that a Markdown file could create multiple pages? This is how. In this example, we paginate over the properties of collections which, as we know, correlates to the tags. By choosing a page size of one, each page will represent its own tag that will get its own page. We use the tag’s name in the permalink to give it a unique url.

The final step is to extract the tag from the url in the layout and use it to filter the collections. You can see this in action in src/layouts/ArchiveLayout.jsx. I will not describe it further. If you’ve made it this far, you will be able to figure it out.

Also, note that I created a special page for /archive that uses the same layout without a tag. This will show all posts.

Interesting tidbits

With pages, collections, and some imagination in your toolbelt, you can build almost anything with 11ty. Before I end this article, though, I will give you a few small tips that improve my 11ty life immensely.

Markdown can contain HTML that can contain Markdown

Most people that use Markdown know that it can contain HTML. That’s great, but I recently learned that HTML in Markdown could, in turn, contain Markdown.

So, for instance.

Some markdown `code`.

<div class="image-wide">

[![Me, with the sun setting over the Gothenburg harbor in the background](/assets/images/about/joakim.jpg)](/assets/images/about/joakim@2x.jpg)

</div>

Notice the whitespace between the <div> and the Markdown? Without it, it will not work! I use this technique when I need special styling of a portion of my content that Markdown doesn’t provide. Also, note that this will wrap the image with a <p>, so be careful when you apply your styling.

Create a Markup component

I’ve used the <Raw> component from hast in the examples. In my actual project, I’ve wrapped this in a Markup component. You’ll find that component among the other components in the demo project.

I do this because sometimes I want to output raw HTML, sometimes I want to tweak the HTML a bit (more on that in a later post), and sometimes I want to output HTML from Markdown. This is useful if you add Markdown in your frontmatter, for instance, or even for the excerpt.

That’s the basics of using 11ty to create a website. In the next article, I will look at other ways of serving content to your users.