FOSS

Simple Offline DOM Search for JAMstack Static Sites.

Often the simplest solution is the best. Comments and search on static sites have long been hurdles for would-be migrations. Instead of relying on an external index and engine like DuckDuckGo or...

#Blog #Jekyll #jQuery

📜 README

Often the simplest solution is the best. Comments and search on static sites have long been hurdles for would-be migrations.

Instead of relying on an external index and engine like DuckDuckGo or Google, or even a dedicated site search system like Algolia, you can use a simple on-page search of hidden meta-data with a few lines of JavaScript via jQuery.

The catch is that all the meta-data you want to search needs to be delivered with the HTML's DOM. This is often fine for a blog and a couple handful of pages but if you need to search MB or more of data this is not the option for you.

The ideal spot for this sort of static offline search is something like a blogs category page, or list of all blog entries (without pagination).

This works with any Static Site generator, I originally made it for Jekyll but it works with 11ty also.

First the search interface above the blog post list. A simple HTML search box (let Pico CSS do the styling):

<input type="search" id="search-for" placeholder="Search" aria-label="Search">

Then the JavaScript in your blog template header:

  <script src="https://cdn.hopjs.net/npm/[email protected]/dist/jquery.min.js"
  integrity="sha256-/JqT3SQfawRcv/BIHPThkBvs0OEvtFFmqPF/lYI/Cxo=" crossorigin="anonymous"></script>
  
  <script>
    $(function() {
      //# jQuery DOM Search
      //# https://benhoskins.dev/shop/jamstack-jekyll-search/
      function search_dom(query) {
        var query = query.toLowerCase().trim();

        $(".searchable").filter(function() {
          hit = $(this).text().toLowerCase().indexOf(query) > -1;
          $(this).toggle(hit);
        });
      }

      $("#search-for").on("keyup", function() {
        search_dom($(this).val());
      });

      // auto `?search=foo`
      let search_url_query = new URLSearchParams(window.location.search).get('search');
      if (search_url_query) {
        $("#search-for").val(search_url_query);
        $("#search-for").trigger("keyup");
      }
    });
  </script>

Next prepare the meta-data among the blog post listings. e.g. while looping the list of blog posts to display on the page, include all the data you'd like to be able to search.

  <article class="post-item searchable">
    <h3 class="post-item-title sans">
      <a href=" post.url "> $post.data.title </a>
    </h3>
  
    <span style="display:none;" data-info="extra-search-data">
      $post.url
      $post.page.excerpt
    </span>

    <span class="post-item-date"> $post.date </span>

  </article>

Here I've added a hidden span tag containing extra data to include in the search for this item. Just replace the variables starting with "$" your posts data.

Make sure not include too much data here, like a full text of the post. It's best to truncate to a certain length and escape HTML also.

It's a simple as including a searchable class on the element that represents each post, and all data (hidden or visible) within will be searched when the user types in the ID search-for input box.

Any element that is classed as searchable, but does not match the ID search-for input will be hidden from the user, leaving only matching results.

The code also allows you to pass a search parameter in the URL to linking to a particular search or filter e.g. "/posts/?search=jquery".

If you'd like to support my work and passion projects, please consider donating the price of my next coffee or whatever you fancy.

❤️ Donate