As my readers know, I've been falling in love with Alpine.js lately and am always on the hunt for more ways to practice using the framework. I thought I'd share an example of how you could use it with Algolia's JavaScript client. I use that on my search page here with Vue.js, so it wasn't a terribly difficult thing to rebuild a similar interface in Alpine.js. Here's how I did it.

The Layout

For the layout, I went with a simple search interface and results that displayed the title, date, and a snippet for each result. Here's that HTML with Alpine.js directives throughout:

<div x-data="app" x-cloak>
    <input type="search" x-model="term">
    <button @click="search" :disabled="!searchReady">Search</button>
    <div x-show="noResults">
            Sorry, but there were no results.
    <div x-show="results">
            There were <span x-text="totalHits"></span> total matches. Returning the first <span x-text="resultsPerPage"></span> results:
        <template x-for="result in results">
                <a :href="result.url"><span x-text="result.title"></span></a> (posted <span x-text=""></span>)
                <p class="snippet" x-html="result.snippet"></p>

From the top, the first two elements are my search field, using x-model, and a button that will initiate the search. I've got it disabled based on a value searchReady that you will see soon.

The next block handles cases where no results were found.

And then I have a block that shows up when results are ready. I render the total number of hits as well as how many I'm showing. (I could do paging here, and if folks want to see that, just ask.) I then loop over my results making use of the url, title, date, and snippet values.

The JavaScript

Now let's look at the JavaScript code:

const appId = 'WFABFE7Z9Q';
const apiKey = 'd1c88c3f98648a69f11cdd9d5a87de08';
const indexName = 'raymondcamden';

document.addEventListener('alpine:init', () => {'app', () => ({
        init() {
            let client = algoliasearch(appId, apiKey);
            this.index = client.initIndex(indexName);
            this.searchReady = true;
        async search() {
            if(this.term === '') return;
            this.noResults = false;
            console.log(`search for ${this.term}`);
//          let rawResults = await;
            let rawResults = await, { 
                attributesToSnippet: ['content']

            if(rawResults.nbHits === 0) {
                this.noResults = true;
            this.totalHits = rawResults.nbHits;
            this.resultsPerPage = rawResults.hitsPerPage;
            this.results = => {
                h.snippet = h._snippetResult.content.value;
       = new Intl.DateTimeFormat('en-us').format(new Date(;
                return h;

On top, I've got three constants related to Algolia. An application ID, my API token which only has read access, and the name of my index. When Alpine initializes the application, I create an instance of the Algolia index wrapper, and then set my searchReady boolean to true. This will enable that button in HTML.

For search, I do a quick validation of the value, and then just pass it to Algolia. The commented-out line shows how simple this can be if you want the defaults, but I wanted Algolia to create a snippet on the content field so the search results would be a bit nicer.

Finally, I do a bit of work on the results. If none were found, I set the value so that it will get flagged in the HTML. If we have results, I copy over the total hits and per page values. I then map the results to make things a bit easier in the HTML. Specifically, I copy over the snippet to an easier-to-use key, and then I use the Intl object to make the dates a bit nicer.

Here's an example of how it looks, and please note that it's me doing my best at design. Don't blame Alpine or Algolia. ;)

Example search result

If you want to give this a try yourself, play with the CodePen below, and as always, let me know if you've got any questions!

See the Pen Algolia + Alpine example by Raymond Camden (@cfjedimaster) on CodePen.