Search & Filters
✎ Improve this pageJekyllLMS ships two complementary search tools: a site-wide search in the
nav bar (courses + blog + docs), and per-page filtering on /courses/ and
/blog/ (category chips, in-page title search). Both are client-side, no
external search service required.
Site-Wide Search
The magnifying-glass button in the top-right of the nav (next to the GitHub
button) opens a search panel backed by search.json — a Liquid-generated
index of every course, post, and doc’s title, url, and a short excerpt,
built at bundle exec jekyll build time.
assets/js/search.js fetches search.json once (lazily, on first open),
then filters it client-side as you type, matching against title + excerpt and
showing up to 8 results grouped by type (📚 Course / 📝 Blog / 📖 Docs). No
Algolia, Lunr, or other search service — the whole index is typically a few
KB of JSON.
To add another collection to the index, extend the loop in search.json
following the existing site.courses / site.posts / site.docs pattern.
Per-Page Filtering
/courses/ has a working search box and category chips; /blog/ has a
search box — both entirely client-side, filtering DOM elements already
rendered by Jekyll (no JSON fetch, no server round-trip).
assets/js/filter.js exposes one helper, initCardFilter(opts), that wires a
search input and an optional row of category chips to a list of DOM elements:
initCardFilter({
searchInput: document.getElementById('course-search'),
chipsContainer: document.getElementById('course-chips'),
cards: document.querySelectorAll('.catalog-grid .course-card'),
emptyState: document.getElementById('course-empty')
});
It reads data-title and data-category attributes straight off each
card/item — _includes/course-card.html sets these from the course’s front
matter, and blog/index.html sets data-title on each .post-item.
Filtering and searching combine (a chip narrows by category, the search box
narrows by title), and an empty-state message appears when nothing matches.
Note that on /blog/ this only searches the posts on the current page of
pagination — the nav’s site-wide search covers every post regardless of page.
Extending to a New Collection
To add per-page filtering to another listing page:
- Add a
data-title(and any otherdata-*attribute you want to filter on) to each item’s wrapper element. - Add a search
<input>and, optionally, a chips container withdata-cat="..."buttons. - Call
initCardFilter({...})for those elements inside theDOMContentLoadedlistener inassets/js/filter.js.
initCardFilter no-ops if its cards selector matches nothing, so it’s safe
to call unconditionally from the shared script.