KDL works great in eleventy

I’ve got KDL working in 11ty!

KDL 2.0.0 has been finalised. Among the initial supporting JavaScript implementations, @bgotink/kdl has functions to support JSON-in-KDL. Exactly what we need to use KDL to describe data for 11ty.

To enable 11ty to read kdl template front matter and .kdl as a data format here’s the plugin code I’m using:

import {parse} from "@bgotink/kdl/json";

export default function (eleventyConfig) {
	eleventyConfig.addDataExtension(
		"kdl",
		handleKDL.bind(null, parse)
	);
	eleventyConfig.setFrontMatterParsingOptions({
		engines: {
			kdl: handleKDL.bind(null, parse)
		},
	});
	eleventyConfig.setFrontMatterParsingOptions({
		language: "kdl",
	});
}

function handleKDL(parse, input) {
	const data = parse(wrapAsJSONinKDL(input));
	if(process.env.DEBUG === "EleventyKDL") {
		console.dir(data, { depth: Infinity });
	}
	return data;
}

function wrapAsJSONinKDL(input) {
	return String.raw`- {${input}}`;
}

This plugin is loaded into the 11ty config like so:

import eleventyKDL from "./eleventyKDL.mjs";

export default function (eleventyConfig) {
	eleventyConfig.addPlugin(eleventyKDL);
	
};

A simple front matter example:

---
title "KDL in eleventy"
date "2024-12-31"
tags _post 11ty kdl
---

Splitting some hairs

Let me back-pedal for a moment.

KDL is somewhat of a misnomer here. More specifically this is JiK (I like to think it is pronounced a little like “gif” 😉) – a subset of KDL that can be translated to JSON and back.

JiK (like JSON) requires a single top level node – hence why wrapAsJSONinKDL in my plugin wraps the input in - {} (KDL for {}). Without it the JiK front matter above would be:

---
- {
	title "KDL in eleventy"
	date "2024-12-31"
	tags _post 11ty kdl
}
---

To me putting this parent node in the front matter invites sibling nodes – that KDL supports, but JiK does not.

If I was not wrapping my .kdl data files in the same manner I would consider instead using a .jik extension. Maybe there is consequence here if I were using a text editor that knew the difference.

11ty tags in JiK

A quick KDL/JiK example relevant to use in 11ty, specifying with collection tags.

Eleventy allows you to assign a single tag as a string, or multiple in an array. This happens to map beautifully to how KDL handles single line arrays. The example above results in the JSON:

{
	"title": "KDL in eleventy"
	"date": "2024-12-31"
	"tags": ["_post", "11ty", "kdl"]
}

If I was to assign only a single tag, e.g.:

---
tags frontmatter
---

Resulting JSON has no array, and that’s okay:

{
	"tags": "frontmatter"
}

If for some reason I wanted an array regardless of the number of tags, I could use the more explicit syntax:

---
title "KDL in eleventy"
date "2024-12-31"
tags {
	- _post
	- 11ty
	- kdl
}
---

Update: Kat (creator and namesake of KDL) pointed out we can ensure an array from a single item, on a single line, using a type annotation.

---
(array) tags frontmatter
---

By the way, if I wanted an array item with a space the quote marks are necessary:

---
(array) tags "front matter"
---

Markdown in front matter

Applying Markdown to anything but template content in 11ty used to be work until we got the Render plugin e.g. in Nunjucks:

{{ my_markdown_summary | renderContent("md") | safe }} 

I’ve not attempted to use multi line strings in YAML, the significant white space makes it feel very dicey.

To create multi-line strings in KDL we use triple quotes """:

title "Markdown for data"
my_markdown_summary """
	## Markdown heading
	
	- this is an unordered list
	- with *inline* mark-up
	"""

Note the triple quotes are on new lines. I got this wrong the first time I tried it, but rather than having to go back to the docs – the thrown error told me exactly what I had done wrong.

🤗 The “cuddle” in KDL is there for you when you make a mistake.

Read more about why KDL.