search feature for jekyll sites without javascript
Why a No-JavaScript Search Makes Sense
Not every Jekyll site needs a JavaScript-heavy search engine. Many minimalist blogs and documentation sites prefer clean, fast-loading pages with no extra dependencies. A no-JavaScript search also improves accessibility, works on older browsers, and maintains full compatibility with GitHub Pages.
The Concept Behind a Static Search
Since Jekyll is a static site generator, all content is available at build time. This means we can generate a static HTML search index during the build, and use basic HTML form actions and anchor links to simulate search functionality. The key lies in offering filtered navigation rather than true text indexing.
Approach: Category-Based Static Search
The simplest and most SEO-friendly method is to mimic search through categories, tags, or titles using pre-built pages and anchor targets. Here's how you can implement this in your Jekyll site.
Step 1: Create a Search Form
Start by adding a basic HTML form that uses the GET method and points to your search results page.
<form action="/search/" method="get"> <input type="text" name="q" placeholder="Search articles..." /> <button type="submit">Search</button> </form>
Step 2: Generate a Search Index Page
Create a page at search.html or search.md. In this page, you’ll filter posts by checking if the query exists in the title.
---
layout: default
title: "Search Results"
permalink: /search/
---
{% raw %}
{% assign query = page.q | downcase %}
{% if query %}
<h2>Results for '{{ query }}'</h2>
{% assign results = site.posts | where_exp: "post", "post.title contains query" %}
{% for post in results %}
<h3><a href="{{ post.url }}">{{ post.title }}</a></h3>
<p>{{ post.excerpt }}</p>
{% endfor %}
{% if results == empty %}
<p>No posts found.</p>
{% endif %}
{% else %}
<p>Please enter a search query.</p>
{% endif %}
{% endraw %}
Step 3: Search by Category or Tag Instead
If title search feels too limited, a better approach is to structure your content around categories and tags, then redirect the query into a known list of options. For instance:
{% raw %}
{% assign query = page.q | downcase %}
{% if query == "seo" %}
{% include_relative categories/seo.html %}
{% elsif query == "email" %}
{% include_relative categories/email.html %}
{% else %}
<p>No results found.</p>
{% endif %}
{% endraw %}
Alternative: Use Lunr.js with Fallback
If you want full-text search but still want to support no-JS browsers, you can serve a JSON search index at /search.json for Lunr.js and keep the static version as fallback. This gives you the best of both worlds.
Case Study: Accessibility-Focused Personal Blog
A minimalist blog about digital ethics implemented a no-JavaScript search to cater to older devices and screen readers. By using tag-based filtered pages with simple form navigation, the site remained 100% accessible and required no scripts or frameworks — yet helped visitors quickly find posts on privacy, surveillance, or censorship topics.
Performance Benefits
- Zero external dependencies
- Compatible with GitHub Pages and Netlify
- Instant load times even on mobile or slow networks
- Improved security and accessibility
Limitations of This Method
This approach only works for basic search tasks like filtering by title, category, or tag. It doesn't support full-text or fuzzy search and requires a limited query vocabulary.
Conclusion
A JavaScript-free search feature is entirely possible with Jekyll. While limited, it's highly effective for simple sites with structured content. If your blog emphasizes SEO, speed, and accessibility, this approach could be a perfect fit without relying on client-side scripting or third-party services.