How to create a drafts page for an 11ty blog

One of the challenges with a statically-generated blog is content management based on properties. Everything is a set of flat files and I’m limited to folders and file names, because that’s what shows up in the terminal or the sidebar of my editor. And I don’t use a drafts folder, so keeping track of drafts is tough.

To make things easier I set up a page that lists a collection of drafts using 11ty’s Collection API. If my post is a draft, I update my frontmatter to include draft: true.

---
title: How to create a drafts page for an 11ty blog
date: 2023-09-13T20:42:26-05:00
tags:
- 11ty
- javascript
draft: true
---

In eleventy.config.js, I created a new collection that gets all collection items and then filters the collection to return just the ones with the draft property set to true. Then it sorts the collection from newest to oldest.

eleventyConfig.addCollection("drafts", function (collectionApi) {
	return collectionApi
		.getAll()
		.filter(item => item.data.draft)
		.sort((a, b) => b.date - a.date);
});

Next, I created a drafts page where I can view a list of links to all my drafts. I’m using JavaScript templates for this blog.

content/drafts.11ty.js

/**
 * @file Template for the drafts page.
 */

/**
 * Frontmatter and markup
 * @see {@link https://www.11ty.dev/docs/data-frontmatter/ 11ty docs}
 * @see {@link https://www.11ty.dev/docs/languages/javascript/#optional-data-method 11ty docs}
 */
exports.data = {
	title: "Drafts",
	layout: "layouts/page.11ty.js",
	tags: "page",
	eleventyExcludeFromCollections: true
};
exports.render = function (data) {
	let posts = data.collections.drafts;
	return `
		<ul>
		${posts
			.map((post) => `<li><a href="${post.url}">${post.data.title}</a></li>`)
			.join("")}
		</ul>`;
}

This is the finished result:

A screenshot of the drafts page listing a list of drafts I will never finish