Combining Tags and Categories for Smart Index Navigation
Why Merge Tags and Categories in Jekyll
Most Jekyll sites separate tags and categories into distinct navigation paths. Categories are often shown in sidebars or menus, while tags live in post metadata or isolated tag pages. This division creates friction for users who want to browse content naturally based on relevance or context.
By combining both systems in one smart index, we allow visitors to explore both hierarchical and associative relationships between content items. This results in better usability, discoverability, and even SEO improvements due to internal link clustering.
Use Case: A Developer Knowledge Base
Let’s say we’re building a knowledge base for developers using Jekyll collections. Each resource item belongs to a category like “Performance” or “Theming,” and also has tags such as “includes,” “scss,” or “responsive.”
Our goal is to create an index that looks like this:
- Performance (category)
- includes (tag)
Step 1: Define Category and Tag Structure in Front Matter
Each document in _resources should include both a category and tags array:
---
title: Optimizing Includes for Speed
category: performance
tags: [includes,html]
---
Step 2: Create Unified Navigation Logic
We’ll use a nested loop: first by category, then by tag, then by content item. To do this efficiently, we build an intermediate data structure in Liquid.
{% raw %}
{% assign category_map = {} %}
{% for item in site.resources %}
{% assign cat = item.category %}
{% for tag in item.tags %}
{% assign key = cat | append: "-" | append: tag %}
{% if category_map[key] %}
{% assign category_map[key] = category_map[key] | push: item %}
{% else %}
{% assign category_map = category_map | merge:
{{ key | jsonify }}: [item] %}
{% endif %}
{% endfor %}
{% endfor %}
{% endraw %}
Unfortunately, complex key mapping like this is limited in Liquid. A more GitHub Pages-compatible approach is grouping in-place during rendering.
Step 3: Group Resources Dynamically During Render
{% raw %}
{% assign categories = site.resources | map: "category" | uniq | sort %}
{% for cat in categories %}
{{ cat | capitalize }}
{% assign by_cat = site.resources | where: "category", cat %}
{% assign tags = by_cat | map: "tags" | join: "," | split: "," | uniq | sort_natural %}
{% for tag in tags %}
{{ tag }}
{% for item in by_cat %}
{% if item.tags contains tag %}
- {{ item.title }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endraw %}
This will print all categories, each with nested tags, and a list of items matching that tag.
Optional: Add Descriptions for Tags and Categories
Create a data file like _data/navigation.yml:
performance:
description: Speed and optimization techniques
tags:
includes: HTML partial reuse best practices
html: HTML-specific tweaks and tips
theming:
description: Design and appearance customization
tags:
scss: Styling Jekyll with Sass
colors: Managing color palettes
Use it in your loop:
{% raw %}
{% for cat in categories %}
{{ cat | capitalize }}
{{ site.data.navigation[cat].description }}
{% assign by_cat = site.resources | where: "category", cat %}
{% assign tags = by_cat | map: "tags" | join: "," | split: "," | uniq | sort_natural %}
{% for tag in tags %}
{{ tag }}
{{ site.data.navigation[cat].tags[tag] }}
{% for item in by_cat %}
{% if item.tags contains tag %}
- {{ item.title }}
{% endif %}
{% endfor %}
{% endfor %}
{% endfor %}
{% endraw %}
Step 4: Improve UX with Jump Index
Allow quick navigation by listing all categories and tags at the top:
{% raw %}
{% for cat in categories %}
- {{ cat }}
{% endfor %}
{% endraw %}
CSS Styling Tips
.jump-nav {
display: flex;
gap: 10px;
flex-wrap: wrap;
padding-bottom: 1em;
}
.jump-nav a {
text-decoration: none;
background: #efefef;
padding: 4px 8px;
border-radius: 5px;
}
h2 {
border-bottom: 2px solid #ddd;
margin-top: 2em;
}
h3 {
margin-top: 1.2em;
color: #444;
}
Benefits of Unified Navigation
- Boosts internal linking across contexts
- Makes relationships more visible to users
- Reduces reliance on search
- Improves crawlability for SEO
Next Steps
You can expand this structure to include:
- Last updated dates
- Content type labels (video, guide, cheat sheet)
- Sort by popularity or recency
Conclusion
Combining tag and category systems into one smart index provides the best of both worlds: structure and flexibility. Jekyll gives you full control over this architecture using nothing but front matter and Liquid templates.
In the next article, we’ll explore how to build a multilingual navigation system using the same tag-category logic translated via YAML data files.
