Client Filtering for Multilingual Jekyll Content
Why Client-Side Filtering is Essential for UX
Static sites often lack the dynamic interactivity users expect, especially when handling complex documentation or blog archives. Adding filtering capabilities on the client side provides instant feedback, speeds up discovery, and gives your multilingual Jekyll site a modern, app-like experience.
This guide shows how to implement live filtering for multilingual content using HTML, JavaScript, and Jekyll’s built-in data structure.
Step 1: Prepare a Structured Content Block
Create a content section with clear language and category tags. Here's a simplified format in your HTML:
<div id="filter-controls">
<select id="language-filter">
<option value="all">All Languages</option>
<option value="en">English</option>
<option value="es">Spanish</option>
<option value="fr">French</option>
</select>
<select id="category-filter">
<option value="all">All Categories</option>
<option value="docs">Docs</option>
<option value="guides">Guides</option>
<option value="reference">Reference</option>
</select>
</div>
<ul id="filtered-list">
<li data-lang="en" data-cat="docs">Getting Started (EN)</li>
<li data-lang="es" data-cat="guides">Instalación rápida (ES)</li>
<li data-lang="fr" data-cat="reference">Référence API (FR)</li>
</ul>
Step 2: JavaScript Filter Logic
Add this script to dynamically show/hide items based on the selected filters:
<script>
document.addEventListener("DOMContentLoaded", () => {
const langFilter = document.getElementById("language-filter");
const catFilter = document.getElementById("category-filter");
const items = document.querySelectorAll("#filtered-list li");
function applyFilters() {
const selectedLang = langFilter.value;
const selectedCat = catFilter.value;
items.forEach(item => {
const langMatch = selectedLang === "all" || item.dataset.lang === selectedLang;
const catMatch = selectedCat === "all" || item.dataset.cat === selectedCat;
item.style.display = langMatch && catMatch ? "" : "none";
});
}
langFilter.addEventListener("change", applyFilters);
catFilter.addEventListener("change", applyFilters);
applyFilters(); // initialize on load
});
</script>
Step 3: Rendering Multilingual Content with Jekyll
Use Liquid to output your posts or docs with appropriate metadata for filtering:
{% raw %}
{% for doc in site.docs %}
<li data-lang="{{ doc.lang }}" data-cat="{{ doc.category }}">
<a href="{{ doc.url }}">{{ doc.title }} ({{ doc.lang | upcase }})</a>
</li>
{% endfor %}
{% endraw %}
Ensure each document has front matter like this:
lang: es
category: guides
Step 4: Style the Filters and Results
Apply a bit of CSS for layout and readability:
#filter-controls {
display: flex;
gap: 1rem;
margin-bottom: 1rem;
}
#filtered-list li {
padding: 0.5rem 0;
border-bottom: 1px solid #ccc;
}
Step 5: Extend for Tags or Search
- Add a third dropdown for tags
- Include a search input for live filtering using
includes()on text content - Support combination filtering (language + category + keyword)
For example, add:
const searchInput = document.getElementById("keyword-filter");
searchInput.addEventListener("input", applyFilters);
function applyFilters() {
// ...previous code...
const keyword = searchInput.value.toLowerCase();
items.forEach(item => {
const textMatch = item.textContent.toLowerCase().includes(keyword);
const show = langMatch && catMatch && textMatch;
item.style.display = show ? "" : "none";
});
}
Step 6: Translate Filter UI for Each Language
If your site supports multiple languages, localize the filter labels using _data files:
_data/ui/en.yml
filter_language: "Filter by language"
filter_category: "Filter by category"
_data/ui/es.yml
filter_language: "Filtrar por idioma"
filter_category: "Filtrar por categoría"
Then include localized labels:
{% raw %}
<label>{{ site.data.ui[page.lang].filter_language }}</label>
{% endraw %}
Use Case: Interactive Knowledge Base
Imagine a multilingual FAQ or developer documentation with 300+ entries. Users can quickly refine the list to French installation guides or English API references — no reloads, no wait time, and all powered statically via Jekyll and client-side logic.
Bonus: Filtering via URL Parameters
Let users share pre-filtered views:
https://example.com/docs?q=plugin&lang=es&cat=guides
Parse query params and apply initial filters automatically using URLSearchParams.
Conclusion
Client-side filtering brings a big UX improvement to static Jekyll sites. It's lightweight, fast, and compatible with GitHub Pages. When combined with multilingual structures, it creates a powerful browsing experience without the complexity of JavaScript frameworks or dynamic backends.
In the next article, we’ll cover **handling alternate language URLs for SEO and UX**, using the hreflang tag and language switcher components to ensure Google understands your multilingual structure.
