Single-sourcing data into table templates in Jekyll
- Introduction
- End Goal
- Step 1: Store data in YAML
- Step 2: Create your table template
- Step 4: Create an include to pull in your template
- Step 4: Populate the table with your YAML data
- Conclusions
Introduction
I was recently working on defining a lot of response definitions for an API project. Normally I would prefer OpenAPI for defining these fields, but this API doesn’t actually have endpoints exposed to the user; it just has extensive JSON inputs and outputs.
Building out the tables reminded me why I like working with Jekyll so much, and why even after 4+ years of using Jekyll, I’m still pretty content with it.
End Goal
First, here’s an example of the end goal:
A lot of responses have similar fields, so I needed to re-use these definitions in various places in the docs (after each JSON sample). Also, I didn’t want to create a bunch of HTML table code everywhere.
Here’s the process I followed.
Step 1: Store data in YAML
The first step is to store the data for the field definitions in a YAML file. Create a YAML file inside _data
called something like fruit-fields.yml
. In it, list entries like this:
apple:
field: "<code>apple</code>"
description: >
<p>A round red fruit that tastes tart, sweet, and crisp.</p>
required: false
type: "String"
values: "<p><i>Example</i>: <code>Honeycrisp</code>, <code>Pink Lady</code></p>"
orange:
field: "Orange"
description: >
<p>A small orange-colored fruit divided into sections with a sweet and juicy taste.</p>
required: false
type: "String"
values: "<p><i>Example</i>: <code>Navel</code>, <code>Minneola</code></p>"
The fields you list depend on what you’re describing, obviously. You need to look at your data and figure out what columns you need, and then basically create a property for each column following YAML syntax. I just needed field name, description, required, data type, and values properties.
Step 2: Create your table template
Now create the template for displaying your content. I’m using a table here, and the HTML looks like this:
<table class="grid" style="width: 100%">
<caption></caption>
<colgroup>
<col width="20%" />
<col width="65%" />
<col width="15%" />
</colgroup>
<thead>
<tr class="header">
<th>Field</th>
<th>Description</th>
<th>Data Type</th>
</tr>
</thead>
<tbody>
<tr>
<td><br/>
<span class="tableRequired">required</span></td>
<td></td>
<td></td>
</tr>
</tbody>
</table>
Fortunately, this is all the HTML we actually need.
Step 4: Create an include to pull in your template
The “include” is how you will pull your template into your content. You can pass parameters in your include that will populate the template. (See Passing parameters to includes for details.) The include needs to pass three parameters.
{% include video_skills_table.md items="apple, orange" file="fruit-fields" caption="Fruit Descriptions" %}
You’ll see how the items
, file
, and caption
parameters get populated into the table template in the next step.
Step 4: Populate the table with your YAML data
Now comes the fun part: Use Liquid to populate the template with your table data. You might want to see my YAML tutorial in the context of Jekyll for some more basic tutorials to start.
Here’s how I loop through my table data in this example:
{% assign tableItems = include.items | split: ", " %}
{% assign tableFileParam = {{include.file}} %}
{% assign tableFile = site.data[tableFileParam] %}
<table class="grid" style="width: 100%">
<caption>{{include.caption}}</caption>
<colgroup>
<col width="20%" />
<col width="65%" />
<col width="15%" />
</colgroup>
<thead>
<tr class="header">
<th>Field</th>
<th>Description</th>
<th>Data Type</th>
</tr>
</thead>
<tbody>
{% for entry in tableItems %}
<tr>
<td>{{ tableFile[entry].field }}<br/>
{% if tableFile[entry].required == true %}<span class="tableRequired">required</span>{% endif %}</td>
<td>{{tableFile[entry]description}}
{% if tableFile[entry].values != empty %}{{ tableFile[entry].values }}{% endif %}</td>
<td>{{ tableFile[entry].type }}</td>
</tr>
{% endfor %}
</tbody>
</table>
Here’s what’s going on. The include.items
code gets the items identified in the include (apple, orange
) and splits them into an array based on a comma + space (,
). As an array, the data is now formatted as [apple, orange]
. Most importantly, you can loop through an array.
Next, the tableFileParam
gets the name of the file
parameter specified in the include and then references this is site.data[tableFileParam]
. This dot notation (site.data.filename
) is how you access items stored in _data
in Jekyll. See Data Files for details.
{{include.caption}}
gets the caption
parameter from the include and populates it in the table.
Now we want to get each of the items specified in tableFileParam
and populate each value into site.data[tableFileParam]
. So we loop through this array: {% for entry in tableItems %} ... {% endfor %}
. With each loop, we get get the property for that item: {{ tableFile[entry].field }}
. For the first loop, it looks like this:
site.data.fruit-fields.apple.field
And for the second iteration of the loop:
site.data.fruit-fields.orange.field
The template gets the other properties as desired (e.g., required
, values
, type
).
For values
, some entries have this, some don’t. We only want to show the section if the value is present. So we add a condition:
{% if tableFile[entry].values != empty %} .... {% endif %}
And that’s it. Now creating a new table is as easy as storing definitions in the YAML file and using this include:
{% include video_skills_table.md items="apple, orange" file="fruit-fields" caption="Fruit Descriptions" %}
Conclusions
Although this example showed how to populate a table, you can create any sort of template and populate it from a YAML file. By separating out the data from the presentation, you can create more sophisticated presentation displays that might be otherwise tedious to code and maintain if populating them manually.
About Tom Johnson
I'm an API technical writer based in the Seattle area. On this blog, I write about topics related to technical writing and communication — such as software documentation, API documentation, AI, information architecture, content strategy, writing processes, plain language, tech comm careers, and more. Check out my API documentation course if you're looking for more info about documenting APIs. Or see my posts on AI and AI course section for more on the latest in AI and tech comm.
If you're a technical writer and want to keep on top of the latest trends in the tech comm, be sure to subscribe to email updates below. You can also learn more about me or contact me. Finally, note that the opinions I express on my blog are my own points of view, not that of my employer.