Horse Racing Datasets redesigned

A list of tags for this post.

Finally! It took a while to circle back to the design after having so much fun figuring out how to build it, but the fourth version of Horse Racing Datasets is finally done! Or at least out there in a good place with more improvements to come.

At the end of last year I had a working proof of concept of how to use Airtable with Eleventy and wrote an article detailing all the particulars. At the time I couldn’t figure out how to filter on the on the dataset so I did two extra API calls for recently added listing and to display a random dataset on the homepage. As I mentioned in my last update I have since figured out how to do it all from a single API call, so updating the article goes on the to do list.

I also need to update the project page, until then here’s a bit about some of the improvements and updates…



Being able to do everything from a single API call is not only a big improvement from my initial proof of concept for this version, but an incredibly big improvement from the prior version, which used an API call for each category. This marks a huge step forward in my problem solving abilities, so rather than be mortified by the last version (OK, I’m still a little mortified!), I’m going to be proud of the improvements I’ve made over the last two years.

A lot of this will go in the update of the Airtable and Eleventy article, but here are some particulars on the filtering.

I used the randItem filter from 11ty Rocks to display a “Random Dataset of the Day”. Since Eleventy only pulls from the API on build, I used Zapier to schedule a daily build at Netlify. This displays a new random dataset and picks up any datasets I’ve added to Airtable since the last build, making maintenance a snap.

The All Datasets page displays alphabetically and the sort order is set at Airtable. But on the category pages the default listing is to display by most recently added. With some search engine luck I found this approach and was able to create a filter to sort by title to keep the same approach used on the All Datasets listing.

The filter gets added in eleventy.js

config.addFilter("sortByTitle", arr => {
arr.sort((a, b) => (a.title) > (b.title) ? 1 : -1);
return arr;

And then used in the for loop in the template…

{% for datakey in all | sortByTitle %}
{% endfor %}

The set-up is similar for the Recently Added page. The filter gets added in eleventy.js

config.addFilter("sortByNewest", arr => {
arr.sort((b, a) => ( > ( ? 1 : -1);
return arr;

And then used in the template…

{% for datakey in all | sortByNewest | limit(5) %}
{% endfor %}

I’m also using the limit filter from 11ty Rocks to set the amount of most recent datasets to return.

Accessibility improvements


In the previous version the header was sticky and navigation sidebar was fixed with scrolling on larger screens. Generally I like this sort of layout for documentation or for browsing listings, but there are issues with screen reflow when zooming out the screen size. The previous version became less usable around 240% zoom.

Prior version of Horse Racing Datasets zoomed to 300%
The previous version zoomed to 300% the layout starts to make the content hard to read.

In the current version everything flows nicely and it’s easy to read all the way up to 500%.

The current version of Horse Racing Datasets zoomed to 300%
The current version zoomed to 300% and everything is easy to read.

Other improvements include visible focus states and color contrast that meets WCAG AA standards in both the light and dark mode.

Horse Racing Datasets homepage in light and dark modes
Light and dark mode.

The current set up uses the visitor’s system-level settings, but I want to add to add the ability toggle sooner rather than later. I tried to implement the Piccalilli user controlled dark or light mode with no luck. I already had the current implementation working by time I tried it, and I’m also using a LOT of custom properties for the themes, but I think my lack of JavaScript skill was the real culprit. Rather than hold up the latest version I decided I’ll put this one on the to do list and come back to it.

Progressive enhancements


The menu toggle is simple yet progressively enhanced to work when JavaScript is disabled or fails to load. It uses the “no-js” fallback approach, which can easily cause accessibility issues. I tested in VoiceOver as well as keyboard-only with JavaScript enabled and disabled and it worked well. My testing was very limited, but hopefully it will work well for everyone.

For a more robust and bulletproof approach Andy Bell has a great premium tutorial at Piccalilli. The membership price recently dropped making it easier to avail yourself of top-notch educational content! I want to improve my JavaScript skills to really understand more about resizeObserver and other more advanced topics before I try my hand at that one. But for now I feel like the site offers a good experience.

Filed under “know thy audience”, when doing any horse racing related project I make sure to do a quick pass in IE11 on my work machine (don’t ask!). The core horse racing audience generally skews older and is less likely to keep their devices up to date. Since I use custom properties the site pretty much renders as black and white in IE11. I have shadows on the dataset container and tags, and originally had them directly in their respective class selectors. They looked a bit odd in the “no color” version so I moved them to custom properties to keep them from rendering in IE11. This site basically looks like a generic food label in IE, and I have to admit that I kind of like it.

Horse Racing Datasets homepage in IE11
The homepage in IE11, reminiscent of generic food labels.

I also took a quick look with Edge on my work machine and was surprised to discover that it was an older version (44). I discovered this because the spacing was off in several areas and I realized that clamp() was not supported in that version. I should’ve thought of this level of progressive enhancement before, but it lead me to figure out that defaults can be set in combination with clamp(), which allows unsupported browsers to pick-up the non-clamp property.

.dataset-container {
background: var(--dataset-bg);
padding: 1rem;
padding: clamp(1rem, 2vw, 1.25rem);
border: 1px solid var(--dataset-border);
box-shadow: var(--shadow-lg);

In the above example browsers that don’t support clamp() use padding: 1rem while the others use clamp().

Performance improvements


Performance improvements are no surprise when going from a site that did an API call on every page to a static site. But it did surprise me that the previous version’s performance scores weren’t worse, not that they’re good, but I imagined much worse.

Before and after Lighthouse scores. Before: Performance 89, Accessibility 100, Best Practices 93, SEO 88. After 100 for each category.
From just OK to perfect scores. Friendly reminder, perfect Lighthouse scores don't mean perfect sites!

The performance metrics show the details of the improvements…

Performance MetricPrevious VersionCurrent Version
First Contentful Paint1.5s0.8s
Speed Index1.7s0.8s
Largest Contentful Paint3.2s1.7s
Time to Interactive3.5s0.8s
Total Blocking Time160ms0
Cumulative Layout Shift0.1130.01

Another area of performance improvement was moving from Tailwind CSS to handwritten CSS. Tailwind isn’t necessarily a performance issue, but I used it as is with no optimization, mostly because I didn’t (and arguably still don’t!) know how to use build tools.

Here’s a comparison using CSS Stats

CSS StatPrevious VersionCurrent Version
File size566kb8kb
Gzipped file size77kb2kb
Pseudo class3,83719
Pseudo element125

No surprises that there were drastic reductions, you can also view the full stats for the All Datasets listing page at CSS Stats.



As mentioned in the Filtering section, I set up daily build at Netlify using Zapier. API calls are only made at build time, so this ensures that there will be a new Random Dataset of Day on the homepage and that any datasets I’ve added to Airtable will picked up daily.

I changed a couple of urls from the previous version so I set up redirects for those changes. Netlify offers a couple of different approaches to handle redirects. I went with the redirects file. To make sure it ends up in the directory that’s deployed I added this to my eleventy.js file…


Finally, I wasn’t originally going to have individual pages for each dataset, but I realized this would make it easier to share and reference them. I used this handy approach from the Eleventy Docs.

What’s next


Knocking this one off the list was a big accomplishment, but there’s always something else to do. Here’s what I’ll be focusing on next.

A list of tags for this post.

Enjoying this site? Leave me a tip at Ko-fi!

Back to top