Astro Templates for JSON Data
Part of the Astro series
Web frameworks like Astro often allow the use of Markdown for blog post “content”, that is, the actual blog post, and then the page design and programming is in a page template which takes the Markdown and renders its contents in the appropriate place for a fully rendered HTML page. This is convenient and allows excellent separation of written words (“content”) and site rendering mechanisms.
Sometimes, though, what you want to put on the page is more complicated than you can easily do in Markdown. Such is the case with my /uses page on this website.
Contents
Background
When I first created my /uses page, I thought I was going to do the same thing I do for my /links and /now pages… namely, use Markdown for the “data” (please don’t make me say content again) which would go into the Astro <Content />
component to render the Markdown into HTML.
But…
As Jason from Hemispheric Views stated rather enthusiastically during a recent episode, Markdown isn’t always the right tool for the job. And it’s NOT the right tool for the /uses job, because I want a format and flexibility for this page that Markdown makes difficult, if not impossible.
The result is that I created the /now page as an Astro page template with all the “data” (no, I will NOT) thrown in amongst the html tags, just like 1990 calling for its beautiful, manually handwritten pages back. But that’s gross. It’s gross because it’s harder to work with from an adding and editing perspective, and it just seems dumb.
The solution is very simple, and it’s what I do on Friends with Beer for the drinks. I use a JSON data file and render it in different Astro page templates.
The Starting Point
My original uses.astro
file looks like this:
The text that is the whole point of the page, namely the items that I use that I wish to present, are just more stuff in a sea of rendering implementation.
You can see for yourself how un-fun it would be to add new items to or edit existing ones. It requires carefully trawling through everything and make sure I’m not messing up nested divs and all kinds of junk. Even with VSCode’s code folding and syntax highlighting, it’s still ugly and nightmarish.
Let’s fix this mess by breaking out the data from the drawing, so to speak.
The Modifications
A JSON Is Born
Step 1 is creating a data file for the stuff I use. I’m calling it uses.json
, and I’m putting it in my data folder at src/data/uses.json
.
Step 2 is figuring out the data structure. I break my stuff up into categories or sections, like “Computer” and “Podcast Recording”.1
You can see that in each category, there are multiple items. Each item consists of:
- The name of the item,
- Some specs,
- An optional link to a website for the item,
- My thoughts about it, aka a description,
- An image of the item.
Based on that, here’s how I’ll structure my JSON data file.
This lets me have multiple categories, each with multiple items, each with the item data listed above.
Then I just have to modify my uses.astro
page template to read it in and map it out to the template I’m using for the “data” section.
An Astro Page Template Gets Smarter
I lied just a little bit. I am going to modify uses.astro
to parse the JSON data from uses.json
, but I’m also going to create an Astro component called UsesItem.astro
that will be used to render the individual items. So uses.astro
is going to load the JSON file, map through the categories, and every time it hits a list of items, it’s going to hand the rendering for them over to the UsesItem.astro
component.
This will break it things up, make re-use easier if I ever want to render any of these items elsewhere, and generally make me happier. And I like being happier.
Here’s what the /uses page template, uses.astro
, looks like now with this approach:
All the information, or data, or content, about the items is GONE from the html template. It’s all in the JSON file, and uses.astro
is just a set of display instructions.
Now the only part that’s hard-coded into the page template is the page introduction area indicated by the rectangle marker below, which is right at the beginning of the <article>
section.
Everything following it comes from the JSON file and is mapped out in this section:
Very little of the work of rendering the items is done in uses.astro
. Instead, it relies on the UsesItem
component which it imports from UsesItem.astro
. The current item in the map loop is passed as a prop to the component, which then renders the item detail view. Here’s my UsesItem.astro
component in its entirety, and half of it is CSS:
This uses the astro:assets Image component to optimize the item’s image as specified in uses.json
. It puts this next to the item name and a list of item features of specs. Under that is my description of what it is or why I like it, followed by an optional link to a website for the item.
You can see that item.Specs
is an array and so I use item.Specs.map
to create the list of specs. Also notice where the item URL link is rendered starts with item.Link &&
which means the following href rendering only happens if item.Link
indeed exists.
The end result that is rendered is something like the following:
Summarium
You can definitely use Markdown for site content when appropriate, such as for a standard blog post. For anything more complicated, though, you’ll want to use a data source, like a JSON file, and a page template to parse it and map it. This way your data, or “content”, is separate from the rendering mechanics, but can be laid out on the page more intricately than is possible with a straight Markdown to HTML rendering.
The good news is that Astro page templates and components are super flexible in terms of easily mixing HTML, CSS, and JavaScript, and they’re the right tool to use for a one-off page with a custom layout.
Footnotes
-
That’s all I have right now because instead of adding things I use, I’m busy rewriting how the page is created. ↩