- Stable
3.0.0
Toggle Menu
1.93s
22.90s
Computed Data
Contents
At the end of the Data Cascade you may want to inject Data properties into your data object that are based on other data values. To do that you can use the new eleventyComputed
feature.
layout
, pagination
, tags
etc.). These restrictions may be relaxed over time.Real World Example
Say you want to use Eleventy’s Navigation Plugin to create a navigation menu for your site. This plugin relies on the eleventyNavigation
object to be set. You don’t necessarily want to set this object manually in front matter in each individual source file. This is where Computed Data comes in!
Consider a blog post with the following front matter format:
---
title: My Page Title
parent: My Parent Key
---
If this file is generated by a Content Management System (like Netlify CMS, in my particular case), I may not be able to (or want to) create the eleventyNavigation
object for each of them. I would also not be able to just dump a standard Data Directory File in there either (that would be useful for setting defaults but we don’t want the same values for every markdown file). eleventyNavigation
properties must be set based on other data properties.
Instead, I created this Data Directory File using eleventyComputed
:
export default {
eleventyComputed: {
eleventyNavigation: {
key: (data) => data.title,
parent: (data) => data.parent,
},
},
};
module.exports = {
eleventyComputed: {
eleventyNavigation: {
key: (data) => data.title,
parent: (data) => data.parent,
},
},
};
eleventyComputed
properties, you must use either JavaScript front matter or a JavaScript data file (template, directory, or global). YAML and JSON do not support JavaScript functions.The resulting data for each posts/*.md
file when processed by Eleventy has the following structure:
{
"title": "My Page Title",
"parent": "My Parent Key",
"eleventyNavigation": {
"key": "My Page Title",
"parent": "My Parent Key"
}
}
If I wanted this data to be computed for all files, I could instead create the following eleventyComputed.js
global data file.
export default {
eleventyNavigation: {
key: (data) => data.title,
parent: (data) => data.parent,
},
};
module.exports = {
eleventyNavigation: {
key: (data) => data.title,
parent: (data) => data.parent,
},
};
Using JavaScript
Use any arbitrary JavaScript for an eleventyComputed
property. Note that JavaScript functions require either JavaScript front matter or a JavaScript data file (template, directory, or global). YAML and JSON do not support JavaScript functions.
Here’s a bunch of examples:
export default {
eleventyComputed: {
myTemplateString: "This is assumed to be a template string!",
myString: (data) => "This is a string!",
myFunction: (data) => `This is a string using ${data.someValue}.`,
myAsyncFunction: async (data) => await someAsyncThing(),
myPromise: (data) => {
return new Promise((resolve) => {
setTimeout(() => resolve("100ms DELAYED HELLO"), 100);
});
},
},
};
module.exports = {
eleventyComputed: {
myTemplateString: "This is assumed to be a template string!",
myString: (data) => "This is a string!",
myFunction: (data) => `This is a string using ${data.someValue}.`,
myAsyncFunction: async (data) => await someAsyncThing(),
myPromise: (data) => {
return new Promise((resolve) => {
setTimeout(() => resolve("100ms DELAYED HELLO"), 100);
});
},
},
};
Using a Template String
If you want to use eleventyComputed in YAML front matter, you can use the template syntax string that matches the syntax of the template.
This is how permalink
works, if you’re already familiar with that.
Consider our first example, but using Nunjucks (this example is also valid Liquid syntax).
---
title: My Page Title
parent: My Parent Key
eleventyComputed:
eleventyNavigation:
key: "{{ title }}"
parent: "{{ parent }}"
---
The above would also resolve to the same Data Cascade:
{
"title": "My Page Title",
"parent": "My Parent Key",
"eleventyNavigation": {
"key": "My Page Title",
"parent": "My Parent Key"
}
}
Advanced Details
We put a lot of work into making this feature as easy to use as possible. Most of these details shouldn’t matter to you as it should Just Work™. But here’s a few things we thought of already and handle in a good way:
- You can put your
eleventyComputed
values anywhere in the Data Cascade: Front Matter, any Data Files (you could even make aneleventyComputed.js
global data file if you wanted to set this for your entire site). - You can read and use any of the existing data properties (including ones created by Eleventy like
page
).- You can use or set
permalink
ineleventyComputed
and it will work (permalink
is a top-level special case computed property anyway). Setting other special Eleventy data keys are not yet supported.
- You can use or set
- You can use a computed property that depends on other computed properties (just reference them like they were any other property
data.propName
and ⚠️ notdata.eleventyComputed.propName
)- The order of the keys in the object doesn’t matter—we smartly figure out what order these should be computed in.
- We will let you know if you have circular references (
key1
uses onkey2
which useskey1
again) - When we calculate the dependency graph for your variable references, we may get it wrong if your references to other computed properties are nested inside of conditional logic. Read more at Declaring your Dependencies.
- You can use a nested object of any depth. It can mix, match, and merge with the standard (non-computed) data. This will always do deep merging (independent of your Data Deep Merge configuration).
- You can reuse and override properties at the same time. In the following example
key
will haveThis Is My Key
as its value.
---
key: My Key
eleventyComputed:
key: "This Is {{ key }}"
---
Declaring Your Dependencies
We do try our best to automatically detect dependencies between eleventyComputed
keys, but it isn’t always 100% accurate—especially if you include conditional logic that only uses another Computed Data key inside of a conditional block. To workaround this issue, you can always declare your dependencies inside of your callback so that it resolves correctly. To do so, just access the variables that your callback uses in the callback function.
export default {
eleventyComputed: {
myValue: () => "Hi",
myOtherValue: () => "Bye",
usesAllTheThings: (data) => {
// We detect this as a declared dependency
data.myValue;
// You can use as many as you want.
data.myOtherValue;
// You could use any valid JS syntax to access them.
[data.myValue, data.myOtherValue];
return `How are you?`;
},
},
};
module.exports = {
eleventyComputed: {
myValue: () => "Hi",
myOtherValue: () => "Bye",
usesAllTheThings: (data) => {
// We detect this as a declared dependency
data.myValue;
// You can use as many as you want.
data.myOtherValue;
// You could use any valid JS syntax to access them.
[data.myValue, data.myOtherValue];
return `How are you?`;
},
},
};
If you suspect Eleventy has the Computed Data order wrong—you can double check what variables Eleventy detects inside of a Computed Data function in the debug output.