Integrate Fuse.js with Statamic

March 27, 2024 · 4 min read

In this blog post, we’ll look at how to improve the search feature of your Statamic site by using Fuse.js with Alpine.js. Fuse.js is a great, light JavaScript library for fuzzy searching, which is perfect for adding better search features to your website. When you use it with Alpine.js and Statamic, you can make a smooth and responsive search experience for your visitors. This is helpful if you have an SSG site.
Fuzzy Search with Fuse.js and Alpine.js in Statamic
We’ll work in the Site.js file, where we build the logic to show search results. Alpine.js will help us handle the reactive components and user input.
To use Fuse.js for searching, we need a dataset to search against. This dataset should be in a JSON format, accessible to our JavaScript code. In our case, we’ll be using a JSON file that contains all the searchable content of our Statamic site.
Setting up the Environment
Before we start, make sure Alpine.js is installed in your project. You can add it with Fuse.js and Axios, which we’ll use to get data, by running these commands:
npm install alpinejs fuse.js axios
Creating the Searchable Data File
Before we can perform any search operations, we need to generate the /search/data.json file. This file will hold the data that Fuse.js will search through, such as titles, categories, and tags of all posts. To automate the creation and updating of this JSON file, we can use Statamic’s event system, specifically the EntrySaved event.
For detailed instructions on how to set up an event listener to generate and refresh the /search/data.json file, refer to our blog post Event Listeners for Statamic. There, we explain how to create a custom event listener that triggers whenever a new post is added or an existing one is updated, keeping your search data up to date.
Setup the search
Here’s how to set up the search functionality. We create a Laravel listener with the following command:php artisan make:listener SavePostsToJson
Modify the SavePostsToJson.php file to include the following code:
namespace App\Listeners;
use Statamic\Facades\Entry;
use Statamic\Events\EntrySaved;
class SavePostsToJson
{
public function handle(EntrySaved $event)
{
$data = Entry::query()
->where('collection', 'news')
->get()
->transform(function ($post) {
return [
'title' => $post->title,
'url' => $post->url,
// Searches for relevant information based on the given query string.
];
})
->toArray();
file_put_contents(public_path() . '/search/data.json', json_encode($data));
}
}Modify the EventServiceProvider.php file to include the created event listener:
namespace App\Providers;
use Illuminate\Auth\Events\Registered;
use Illuminate\Auth\Listeners\SendEmailVerificationNotification;
use Illuminate\Foundation\Support\Providers\EventServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Event;
use App\Listeners\SavePostsToJson;
use Statamic\Events\EntrySaved;
class EventServiceProvider extends ServiceProvider
{
/**
* The event listener mappings for the application.
*
* @var array
*/
protected $listen = [
Registered::class => [
SendEmailVerificationNotification::class,
],
EntrySaved::class => [
SavePostsToJson::class,
]
];
/**
* Register any events for your application.
*
* @return void
*/
public function boot()
{
//
}
}Navigate to the "public" folder in your directory.
Create a new folder within "public" and name it "search".
Inside the "search" folder, create a file named "data.json".
import Alpine from "alpinejs";
import axios from "axios";
import Fuse from "fuse.js";
window.Alpine = Alpine;
Alpine.data("search", () => ({
fuse: null,
search: null,
results: [],
init() {
axios(`/search/data.json`).then((response) => {
this.fuse = new Fuse(response.data, {
includeScore: true,
threshold: 0.4,
keys: ["title"],
});
});
this.$watch("search", () => {
let data = this.fuse.search(this.search);
data = data
.sort((resultA, resultB) => resultA.score - resultB.score)
.map(({ item }) => {
return {
title: item.title,
url: item.url,
};
});
this.results = data;
});
},
}));
Alpine.start();In the above script, we’ve initialized Alpine.js with a search component, which fetches our search data and sets up Fuse.js. It also watches the searchQuery property for changes and updates the results array with the sorted search results accordingly.
Choose the keys for the properties you wish to search through. Here, we’re only searching the title, but you can add more properties to the keys array if needed.
The search interface is defined in the markup as follows:
<div x-data="search">
<input type="text" name="search" x-model="search" placeholder="Search">
<div>
<template x-for="item in results">
<a x-bind:href="item.url">
<p x-text="item.title"></p>
</a>
</template>
<template x-if="search && results.length === 0">
<p>No Results For <span x-text="search"></span>.</p>
</template>
</div>
</div>In this snippet, we’ve created an input field tied to the searchQuery model. We’ve also set up conditional rendering for when there are search results or when no results are found. The x-for directive loops through the results array, displaying each result as a clickable link.
Conclusion
By doing these steps, you’ve given your Statamic site a better search feature that gives quick feedback and improves the user experience. Look at how you can use more advanced searches like Algolia, Meilisearch, and Elasticsearch.
Learn how to integrate Algolia for your Statamic site, from creating an account and configuring search drivers to using JavaScript for lightning-fast search requests directly from the frontend. Algolia offers advanced features that can transform the way users interact with your site’s search function. You can also learn how to integrate Meilisearch with your Statamic site.
Bring Your Ideas to Life 🚀
Kickstart Your Statamic Project with the #1 Statamic Agency
Are you planning a new Statamic project or thinking about migrating your WordPress site to Statamic? Learn more about our expertise as a renowned Statamic development agency.
Technologies

Stay up-to-date
Be updated with all news, products and tips we share!

