Get started

You can use this starter as a template for your blog and you are ready to go! But there are some adjustments you have to make.

If you are working with VS Code I recommend installing the “Tailwind CSS IntelliSense” addon, as it works also for our custom utility classes. That said, you will find that Tailwind CSS does not work as you might expect. I explain this in one of the blog posts.

The blog posts also explain / show some features that aren’t covered here.

“Docs” lol


Add and delete your custom block stylesheets in src/assets/css/blocks/*.css, they get pulled in your output stylesheet automatically.

The methodology used is CUBE CSS.

The CSS system of this starter was invented by Andy Bell.
If you want to know exactly how it all works, and have a look at the (further elaborated) original, read this article on

Design tokens

Edit all your preferences (colors, fluid text sizes etc.) in src/_data/designTokens/*.json.

Additional colors, variants and gradients for custom properties are automatically created in src/assets/css/global/variables.css based on the colors set in colors.json. If you change names you should edit variables.css as well and check if the names are used elsewhere in the template.
Admittedly, I went a little bit crazy there with the new CSS color syntax stuff.

In the style guide you can see how everything turns out.


The favicons used are based on the recommendations from the How to Favicon article on

All favicons are in src/assets/images/favicons, and copied over to the root of the output folder.

There is no automatization in place to create them.

I recommend keeping the file names as they are, since they are referenced like that in different places.


This starter uses three fonts, Red Hat Display, Figtree and Roboto Mono. You can add or delete fonts in src/assets/fonts.

You can create font subsets for a better performance, for example using the Fontsquirrel Webfont Generator.

Next, edit src/assets/css/global/fonts.css.

Add your new font aliases in src/_data/designTokens/fonts.json.

Finally, in src/_layouts/base.njk edit the font preloads. Roboto Mono is only used for code blocks. Its preload is set directly in the post layout: src/_layouts/post.njk.

Less JavaScript

The only “real” JavaScript dependency is theme-toggle.js, which is inlined.

The gallery.njk and details.njk components were slightly enhanced with JavaScript.

There are three more scripts, but you have to opt in:

nav-drawer.js, to opt in to a drawer menu on small screens (Read more in Navigation).

masonry.js, creating the masonry effect used on the cards.
Search for masonry: true to see where it is activated, and set to false, an empty string, or delete the front matter field, if you don’t want to use it. The script won’t be included then. Nothing breaks, the cards just won’t rise up to completely fill the gaps in their grid.

The easteregg.js is an opt-in JS-file set in src/_data/meta.js.
Right to the end of the file, you can set easteregg: false to deactivate the loading of the script.


There is the idea of making masonry layout a native part of CSS grid, using grid-template-rows: masonry;. It is not yet to be seen on the horizon, but it is already included in the starter (inside the grid.css composition).
Until then, a small script will help us to get the effect.

It gets loaded by opt-in.
Set masonry: true in your front matter to activate.

Open Graph images

You can see a preview of the OG images in a blog post.

They are referenced in meta-info.njk:

  content="{{ meta.url }}
  {% if (layout == 'post') %}/assets/og-images/{{ title | slugify }}-preview.jpeg
  {% else %}{{ meta.opengraph_default }}
  {% endif %}"

To change the look and behaviour of those images and replace the SVG background edit src/common/og-images.njk.

The implementation is based on Bernard Nijenhuis article.

If you want to be inspired, have a look at what Lea is doing here.

Previously, the images were created at build time, but this leads to not rendering the font – if the system executing the build has not installed the font, it will not be used.

A solution would be to always build the page yourself and then place it on the server directly.
Or, as Sophie Koonin does, explicitly specify the system to be used for the build, and select a font that this system has installed by default.

At the moment I have relocated the creation of the images in the development process, so that the font only needs to be installed on your own system. The images are located in src/assets/og-images and are comitted.

This is fine as long as you only work with markdown and the font is always installed on your system. How this works if a CMS is involved remains to be seen 😅.

Consider that the domain is a hard coded value in the front matter in src/common/og-images.njk.

Let me know if you encounter any problems.


The blog posts use Eleventy’s pagination feature. The logic for this can be found in the layout src/_layouts/blog.njk, how many entries should be on a page can be defined in src/pages/

If you do not want any pagination at all, it is easiest to set a very high number for the pagination size, for example:

  data: collections.posts
  size: 10000

In src/_data_/meta.js you can set some values for the visible content (previous / next buttons) and the aria labels.

You can also hide the number fields between the previous and next buttons by setting paginationNumbers to false.

blog: {
	// other adjustments
	paginationLabel: 'Blog',
	paginationPage: 'Page',
	paginationPrevious: 'Previous',
	paginationNext: 'Next',
	paginationNumbers: true

If you want to change the collection that is paginated (by default collections.posts), you must do so in two places: the front matter of the template, src/pages/

  data: collections.posts

and where the pagination component is included: src/_layouts/blog.njk:

<!-- set collection to paginate -->
{% set collectionToPaginate = collections.posts %}
<!-- if the number of items in the collection is greater than the number of items shown on one page -->
{% if collectionToPaginate.length > pagination.size %}
<!-- include pagination -->
{% include 'components/pagination.njk' %}
{% endif %}
Platforms (icons)

Find available social media / platform icons in src/_includes/svg (prefixed with platform-).
If you add new icons, prefix their name with “platform-”.

In personal.yaml you can add new platforms and their URLs. The key should be the same as the name of the icon. For example: mastodon: '' and platform-mastodon.svg. features a great variety of free SVG icons for popular brands.


This was probably the most opinionated decision: tags have been integrated since version 2.0.

In several places you will find a code block that looks like this:

<!-- loop posts -->
{% set itemList = collections.posts %}
{% for item in itemList.slice(0, 4) %}
<!-- activate tags -->
{% set activateTags = true %}
<!-- set heading context -->
{% set headingContext = "h3" %}
<!-- card -->
{% include 'components/card.njk' %}
{% endfor %}

card.njk is imported as a component, and some settings are made.
With set activateTags = true you can switch the display of tags in this card collection instance.

The tags are placed in the front matter of the posts, using the syntax

  - image
  - feature


tags: ['markdown', 'feature']

If you generally do not want any tags to show, it is probably easiest to not create any at all.

Theme (dark / light mode)

With version 2.0 I introduced dark and light mode. This is not intended to be a gimmick, but to support the accessibility of the site. And I tend to read blog posts at night, and if there is no dark mode then I leave the tab for later, and we all know how that ends.

Dark and light mode respects the user agent or operating system settings using the prefers-color-scheme CSS media feature. But there is also a switch in the <footer>.

If you want to change something here, for example replace the button with a sun/moon icon, make sure to preserve accessibility.

The accessible name (“Theme dark” or “Theme light”) is put together by aria-labelledby="theme-switcher-label" resolving to “Theme” and the <button>s “light” and “dark”.

If your site is in another language, you can adjust those values in _data/meta.js, for both the content of the <button>s and their aria-label.

If you remove the “light” and “dark” <button> and you don’t use the heading with the ID theme-switcher-label, the value for the accessible name must be obtained differently.

If you find any accessibility issues, please let me know.

What can be deleted

Everything, of course
This is still meant to be a starter, even though it grew to be more like a template.
If you want to keep the defaults, but get rid of the example content, delete the following files and archives:

  • github.js in src/_data/
  • builtwith.json in src/_data/
  • all files in src/posts
  • the directory and all files in src/docs
  • all pages in src/pages, though you might want to keep index.njk as a starting point
  • You can delete screenshots, blog and gallery in src/assets/images.
    Keep the favicon and template folders though.

If you don’t want to feature any code examples, you may delete the whole stylesheet for syntax highlighting: src/assets/css/blocks/code.css.
In general, any CSS block in there is optional.