After the Simple-Jekyll-Search experience I found a perhaps simpler way to do blog search without all the fuzz.
~ 50 lines of generic JavaScript will suffice.
What you need to set up in your HTML code is the following:
- an
<ul>
or<ol>
preferably, but it should work with any element, with the CSS classsearchable
applied <li>
items that represent searchable blog posts (in fact the wholeinnerText
is used to look for search matches)
You can see it in action on /posts/.
Here is how I set up the HTML (a simple list of posts <li>
):
<ol reversed class="searchable">
<li class="post-item">
<time datetime="2020-02-08" class="bg-black text-white">2020-02-08</time>
<a href="/posts/2020-02-08-Simplest-Vanilla-JavaScript-static-site-blog-search-for-Jekyll,-Hugo,-11.ty-eleventy/" class="">
Simplest Vanilla JavaScript static site blog search for Jekyll, Hugo, 11.ty
</a>
</li>
...
</ol>
In my main.js
file I use it this way, by making every .searchable
list a searchable list:
[...document.querySelectorAll('.searchable')]
.forEach(makeSearchable)
Below you can find the full source code:
function makeSearchable ($searchable) {
const $search = document.createElement('input')
$search.setAttribute('class', 'searchable-input')
$search.setAttribute('type', 'test')
$search.setAttribute('placeholder', 'Search posts...')
$search.onkeyup = handleSearchKeyUp
$searchable.parentNode.insertBefore($search, $searchable)
function handleSearchKeyUp (e) {
const searchTerm = e.target.value
const searchRegExp = new RegExp(searchTerm.replace(' ', '.*'), 'i')
const $searchableItems = $searchable.querySelectorAll('li') || []
const postTitles = Array.prototype.map.call($searchableItems, $el => $el.innerText)
const noMatch = postTitles.filter(t => searchRegExp.test(t)).length === 0
let $noMatch = document.getElementById('no-match')
if (noMatch) {
if (!$noMatch) {
$noMatch = document.createElement('div')
$noMatch.setAttribute('id', 'no-match')
$noMatch.innerText = 'No matches'
$searchable.prepend($noMatch)
}
} else {
if ($noMatch) $searchable.removeChild($noMatch)
}
$searchableItems.forEach(function ($postLi) {
const show = noMatch || !searchTerm || searchRegExp.test($postLi.innerText)
if (!show) {
$postLi.style.display = 'none'
} else {
$postLi.style.display = 'list-item'
}
})
}
}
response to extreme gatsby configuration
this is a gatsy
configuration for a blog search I recently found on twitter, from which I was blown away because it seemed soo much for the task to be done.
I’ve found things like IntersectionObserver
, React.useMemo
, useQueryParamState
, React.useState
, React.useEffect
, navigator.clipboard.writeText
, window.history.replaceState
.
Some are good ideas, others, in my opinion, are a bit excessive.