Using global data in 11ty

posted Jan 20, 2024

Global data is data that is accessible throughout your Eleventy project. An example of global data are JSON files that look like this:

[
  {
    "date": "2024-01-19",
    "update": "create shortcodes to add furigana over kanji text. see it in action [here](/site-info)"
  },
  {
    "date": "2024-01-18",
    "update": "remove thin scrollbar to improve accessibility"
  }
]

The code above is a snippet of my updates.json file. Global data files are placed inside the _data folder, which is the default directory, but you’re free to change that in your eleventyConfig.

Each item in updates.json has a date and update property, which contains the values I want to display in my changelog.

With this JSON file, I can automatically render my website’s changelog in the home page and in the changelog page without having to manually type in everything, including the HTML tags. All I need to do is update one file (updates.json).

In the changelog page, all updates are rendered in HTML like so:

<span class="label">Jan 19, 2024</span>
<span>
  <p>create shortcodes to add furigana over kanji text. see it in action <a href="/site-info">here</a></p>
</span>

Which looks like this (as of January 2024):

A screenshot of this website’s changelog page which is a list of sitely updates

Instead of typing out the updates individually with HTML tags, which can be tedious and prone to errors, we can harness the power of for loops and global data files and let the code do everything for us:

{% for update in updates %}
	<span class="label">{{ update.date }} </span>
	<span>{{ update.update }}</span>
{% endfor %}

The code above[1] is placed in any HTML or Markdown file; in this example: changelog.md. When I run npx @11ty/eleventy in the terminal, the code will loop through the updates.json file and render the output with the HTML tags in between.

Let’s go through the code line by line:

{% for update in updates %}

The for keyword will loop through each item in the updates JSON file. For each item, we’ll assign it the variable name update. That means we can now get each item’s date and update properties, as seen in the JSON file.

We access those properties like so:

  • update.date, which contains the date, and
  • update.update, which contains the update text.

<span class="label">{{ update.date }} </span>
<span>{{ update.update }}</span>

Enclose update.date and update.update with {{ }} to print the value in HTML. Then, we use HTML tags as usual, like <span> in the example above.

Run your npx @11ty/eleventy or npm start or whatever, et voilà! It’ll generate your entire list of updates with just four lines! Any time you want to update the changelog, simply add a new item at the top of the JSON file.[2]

If we want to take this further, we can take only the first n number of updates to show in the home page:

A screenshot of the home page which shows only the first four updates

We use the keyword limit to take only the first n items in the JSON array:

{% for update in updates limit:4 %}

In the code above, it will take the first four updates and render that from the index.md page. An important caveat is that the limit keyword is only available in the Liquid templating language. For Nunjucks, you can use the slice() function. See here for more info.

Other use cases

I use global data files for my button wall:

[
  {
    "title": "whiona.me",
    "img": "https://cdn.some.pics/whiona/653868e25e532.png",
    "url": "https://whiona.me"
  },
  {
    "title": "hillhouse.neocities.org",
    "img": "/assets/img/hillhouse-banner-2.gif",
    "url": "https://hillhouse.neocities.org/"
  },
  {
    "title": "frills.dev",
    "img": "/assets/img/frills.png",
    "url": "https://frills.dev"
  }
]

This JSON has three properties: title, img, and url. Using global data in this instance saves me the trouble of having to type out <a href=""><img src="" alt=""></a>. And with the amount of buttons I have on my wall, my hand would’ve cramped from manually typing everything in.

Here’s a code snippet from links.md for reference:

{% for button in button_wall %}
	[![{{ button.title }}]({{ button.img }})]({{ button.url }})
{% endfor %}

or in a more readable HTML format:

{% for button in button_wall %}
  <a href="{{ button.url }}">
    <img src="{{ button.img }}" alt="{{ button.title }}">
  <a/>
{% endfor %}

I also use it in my movie log page! I don’t have individual pages for each movie like I do with my book log[3], so I use global data instead. Here’s a sneak peek of the JSON[4]:

[
  {
    "Title": "The Shape of Water",
    "Directors": ["Guillermo del Toro"],
    "Rating": 5,
    "Genres": ["Romance", "Drama", "Fantasy"],
    "Year": 2017,
    "DateWatched": "2024-01-11",
    "Favourite": true,
    "Rewatch": true
  }
]

And this is how it’s rendered:

A screenshot of the rendered HTML in the movie log, in semi-tabular format

The properties Favourite and Rewatch are checked if true, which then renders the SVG icons. The star rating uses custom 11ty shortcodes to render the star icons from the Rating property.

Other than looping through global data, you can also create a metadata.json file, which contains the site title, author, etc, which you can put in your RSS feed, among other things.

References

Global Data Files — Eleventy


  1. This is a simplified version, of course. The original uses 11ty filters to format the date and render Markdown, which is outside the scope of this post. ↩︎

  2. This also saves you from having to sort the items in reverse chronological order… ↩︎

  3. My book log (and the blog posts) are part of 11ty collections, which is another behemoth altogether. ↩︎

  4. I should probably get rid of the unused properties like Genres, lol. ↩︎