KDL works great in eleventy
- Posted
31 December 2024
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.