Making Pagefind Rerun Search on Browser Back Button

One thing that's bothered me about search on my JAMStack sites is the default behavior when moving through browser history.

Making Pagefind Rerun Search on Browser Back Button

I've been using Pagefind quite happily on my JAMStack sites for quite some time, but one thing that's always bothered me a little bit is the default behavior when moving through browser history.

By default, when you run a search and then click a result all works as you'd expect, but when you click Back in my experience the last entered search term remains populated in the search field, but no search results are displayed - obviously because those get populated dynamically via javascript, and I assume some browser state is keeping the input field filled.

You can force it to run a search if there's a search string in the URL query parameters, I think a lot of people have discovered and implemented that, and it's great especially if you're adding the schema json to make search box available to google (whether they ever choose to enable it for your site or not)

But wouldn't it be great, if instead of a populated search field with no results, or it rerunning a potentially incorrect prior search when you navigate back, if it instead always reran your last search phrase? Whether that was from clicking a link with the search term baked in, using the google search box, or having manually entered a search phrase.

It would be great.. no, it IS great! Just a handful of JS makes it work.. we simply need to add some listeners and update the URL every time it changes, and then along with watching for a value populated to q in the URL, we also need to listen for popstate events to trigger search on back-button navigation.

Here's a bit of code that makes it go:

<script>
  // This assumes you have your baseUrl defined in some site data
  // and that your search page lives at /search/
  // and that your search phrase is defined with the "q" GET parameter
  
  const BASE_URL = '{{ site.baseUrl }}/search/';

  const makeUrl = term =>
    term ? `${BASE_URL}?q=${encodeURIComponent(term)}` : BASE_URL;

  const debounce = (fn, ms = 250) => {
    let t;
    return (...args) => {
      clearTimeout(t);
      t = setTimeout(() => fn(...args), ms);
    };
  };

  window.addEventListener('DOMContentLoaded', () => {
    const pagefind = new PagefindUI({
      autofocus: true,
      element: '#search',
      showSubResults: true,
    });

    const params = new URLSearchParams(location.search);
    const initial = params.get('q') || '';
    if (initial) pagefind.triggerSearch(initial);

    const input = document.querySelector('input.pagefind-ui__search-input');
    const clearButton = document.querySelector('button.pagefind-ui__search-clear')

    input.addEventListener('input', debounce(e => {
      const term = e.target.value.trim();
      history.replaceState({ q: term }, '', makeUrl(term));
    }));

    clearButton.addEventListener('click', debounce(e => {
      history.replaceState({}, '', makeUrl(null));
    }));

    window.addEventListener('popstate', e => {
      const term =
        (e.state && e.state.q) ||
        new URLSearchParams(location.search).get('q') ||
        '';

      input.value = term; 
      if (term) pagefind.triggerSearch(term);
      else clearButton.click();
    });
  });
</script>

Share Tweet Send
0 Comments