Building a Library with CSV in Eleventy
Introduction
On this website, and on many others I’ve seen, people like to track their reading lists. I thought it may be helpful to briefly outline the system I have set up with Eleventy to do this fairly seamlessly.
Data input
In my opinion, tracking data for books should be frictionless. I personally find the .csv format to be the best for most text-based data inputs, the JSON
formatting Eleventy natively uses feels much slower to me. My input data is stored in the _data
folder in Eleventy and looks like the following:
title,author,rating,status
My Struggle,Karl Ove Knausgaard,★★★★★,Read
The Man from the Future,Ananyo Bhattacharya,Reading
This is Not the End of the Book,Umberto Eco,★★★,Read
The Changing World Order,Ray Dalio,★★★★,Read
The Death of Ivan Ilych,Leo Tolstoy,★★★,Read
This is a great start but unfortunately Eleventy does not natively read the .csv file format.
CSV transformation
Using Node, we can install the csv-parse module with npm install csv-parse
. Once installed, add the following .js script to your _data
file:
const parse = require("csv-parse/lib/sync")
const fs = require("fs")
function readCSV() {
const input = fs.readFileSync("./src/site/_data/books.csv")
const records = parse(input, {
columns: true,
skip_empty_lines: true,
})
console.log(`${records.length} books found.`)
return records
}
module.exports = function () {
const data = readCSV()
return data
}
Note: Make sure here that your input filename matches that .csv in your _data
folder.
This file creates a data format that Eleventy can reference now, using the filename as the reference. Let’s look at using this data to create a template.
Nunjucks template
Now that we have usable data for Eleventy to pull from, we can create templates using nunjucks markup. For example, something like {{ "{%- for book in booklist -%}" | escape }}
will use the Javascript file you created (in this case, booklist.js) to create an entry for each line in the .csv file. You can use this to template a list like my reading page, which uses the following html:
{{ "{%- for book in booklist -%}" | escape }}
<div class="collection-items">
<div class="collection-name">
<span class="date">{{ book.author }}</span><br>
<span class="collection-link">{{ book.title }}</span>
</div>
<div class="collection-data">
<span class="data-num">{{ book.rating }}</span>
</div>
{{ "{%- endfor -%}" | escape }}
Conclusion
That’s it! I hope this proved useful for anyone looking to create a fairly straightforward but streamlined data entry process.