Designing Custom Layouts and Filters for Jekyll Collections
Why Custom Layouts and Filters Matter in Jekyll Projects
Once you start organizing your Jekyll content with collections, the next natural step is controlling how those collections are presented. Instead of using a one-size-fits-all layout, custom layouts tailored to each content type improve usability, design, and structure.
In tandem with custom layouts, Liquid filters allow you to sort, group, and transform content dynamically in your templates. This article walks you through real-world examples for combining both techniques to build elegant and flexible sites.
Case Study: Creating a Multi-Level Tutorial Platform
Imagine you're building a tutorial platform where each tutorial has:
- A level (beginner, intermediate, advanced)
- An estimated reading time
- A difficulty badge and progress bar
Your goal is to create a custom layout that highlights this metadata and displays it consistently across the entire _tutorials collection.
Step 1: Define Custom Layout for the Collection
Start by creating a new layout file: _layouts/tutorial.html
{% raw %}
{{ page.title }}
{{ page.title }}
{{ page.difficulty | capitalize }}
Reading Time: {{ page.reading_time }} min
{{ content }}
{% endraw %}
This layout introduces structured display of metadata using front matter like difficulty and reading_time. You can further enhance this by using custom Liquid filters.
Step 2: Apply the Layout in a Collection Item
---
title: Mastering Liquid Filters
difficulty: advanced
reading_time: 7
layout: tutorial
---
With just these three fields, your tutorial file gets a fully branded and styled layout. You can even customize styles with CSS based on .badge-advanced, .badge-beginner, etc.
Step 3: Filter Tutorials on the Listing Page
On your tutorials.html page, you may want to group or highlight tutorials based on difficulty:
{% raw %}Advanced Tutorials
{% for tut in site.tutorials %}
{% if tut.difficulty == "advanced" %}
- {{ tut.title }} ({{ tut.reading_time }} min)
{% endif %}
{% endfor %}
{% endraw %}
This is basic filtering logic using built-in Liquid conditionals. But let’s take this further.
Using Custom Liquid Filters (Advanced Technique)
Jekyll doesn’t support custom Liquid filters on GitHub Pages unless you use plugins locally. But you can emulate filter-like behavior by using assign, where, and sort.
Sorting by Reading Time
{% raw %}{% assign sorted_tuts = site.tutorials | sort: "reading_time" %}
{% for tut in sorted_tuts %}
{{ tut.title }} - {{ tut.reading_time }} minutes
{% endfor %}{% endraw %}
Grouping by Difficulty
{% raw %}{% assign levels = "beginner,intermediate,advanced" | split: "," %}
{% for level in levels %}
{{ level | capitalize }}
{% for tut in site.tutorials %}
{% if tut.difficulty == level %}
- {{ tut.title }}
{% endif %}
{% endfor %}
{% endfor %}{% endraw %}
This allows for structured group display without requiring hard-coded blocks per difficulty level.
Combining with Front Matter Defaults
To reduce repetition, you can predefine default front matter for tutorials in _config.yml:
defaults:
- scope:
path: "_tutorials"
values:
layout: tutorial
difficulty: intermediate
Now you only need to override values when necessary in the individual tutorial files.
Case Study: Portfolio Projects with Custom Layouts
If you have a portfolio collection, each project can have a unique layout showing:
- Tags (e.g., "React", "Node.js")
- Screenshots in a gallery
- A GitHub or live demo link
Example front matter:
---
title: Weather Dashboard
tags: [React, API]
screenshots:
- /img/weather-1.png
- /img/weather-2.png
github: https://github.com/user/weather
layout: project
---
In _layouts/project.html:
{% raw %}{{ page.title }}
{% for shot in page.screenshots %}
{% endfor %}
{% if page.github %}
View on GitHub
{% endif %}{% endraw %}
This dynamic layout makes it easy to standardize how project content is presented while still allowing for variation in fields.
Client-Side Filtering Using JSON and Liquid
To add client-side interactivity without a JavaScript framework, you can generate a JSON file from your collection:
# _plugins/json-generator.rb (for local builds)
require 'json'
module Jekyll
class JSONGenerator < Generator
safe true
def generate(site)
tutorials = site.collections['tutorials'].docs.map do |doc|
{
title: doc.data['title'],
url: doc.url,
difficulty: doc.data['difficulty'],
reading_time: doc.data['reading_time']
}
end
File.open('tutorials.json', 'w') do |f|
f.write(JSON.pretty_generate(tutorials))
end
end
end
end
Now use JavaScript to fetch and filter tutorials dynamically on the frontend.
Conclusion
Custom layouts and Liquid filters unlock the full potential of structured content in Jekyll. By tailoring the layout and behavior of each collection type, you not only improve user experience but also gain editorial control and scalability for your site.
In the next article, we’ll go even deeper and explore how to build an interactive search interface for collections using client-side JavaScript and JSON output, while still maintaining a fully static GitHub Pages deployment.
