The search.js
file is used to manage the Algolia search integration and experience.
How it Works #
This script automatically toggles the view of a regular page versus the search page when a user inputs a search string. With every added letter, a new search is performed against the index.
Results returned are grouped by parent article and then provided as a stacked series of links.
Set Up #
- Create an Algolia account.
- Provide your App ID and Search Only API Key to the
searchClient
(these are safe to reveal; the Admin API Key is not.). - Push or upload your site’s index, found at /index.json.
That’s it! Start searching.
I personally just download this file and upload it per release; it’s a manual process — but super easy. You are welcome to integrate the Algolia API with your Admin API Key to push auto updates.
There are several ways to implement Algolia; DocSearch is popular and free. I personally like to integrate the style of the UX more, but this can require more knowledge of InstantSearch.js
.
If you like the default implementation but wish to style the search hits differently, you can do so in the performAlgoliaSearch(query)
function.
Source Code #
document.addEventListener("DOMContentLoaded", function () {
const searchInput = document.getElementById("searchInput");
const pageContainer = document.getElementById("pageContainer");
const searchResultsContainer = document.getElementById(
"searchResultsContainer"
);
// Algolia configuration
const searchClient = algoliasearch(
"4TYL7GJO66", // APP ID
"4b6a7e6e3a2cf663b3e4f8a372e8453a" // Search Only API Key
);
const searchIndex = searchClient.initIndex("default"); // Replace 'default' with your Algolia index name
// Function to group search results by parent
function groupResultsByParent(hits) {
const groupedResults = {};
hits.forEach((hit) => {
const parent = hit.parent;
if (!groupedResults[parent]) {
groupedResults[parent] = [];
}
groupedResults[parent].push(hit);
});
return groupedResults;
}
// Function to perform Algolia search and update results with more details
function performAlgoliaSearch(query) {
searchIndex
.search(query)
.then(({ hits }) => {
// Group search results by parent
const groupedResults = groupResultsByParent(hits);
// Display grouped search results in the search results container
const resultsHTML = Object.keys(groupedResults).map((parent) => {
const parentResults = groupedResults[parent];
const parentHTML = parentResults
.map((hit) => {
return `
<a href="${hit.relURI}">
<div class="mb-4 text-black hover:bg-brand hover:text-white rounded-lg p-4 my-2 bg-zinc-100 transition duration-300 shadow-md">
<h3 class="text-lg font-bold">${hit.title}</h3>
<p class="text-sm text-zinc-200">${hit.description}</p>
</div>
</a>
`;
})
.join("");
return `
<div class="mb-8">
<h2 class="text-xl font-bold text-black">${parent}</h2>
${parentHTML}
</div>
`;
});
searchResultsContainer.innerHTML = resultsHTML.join("");
})
.catch((err) => {
console.error(err);
});
}
// Event listener for typing in the search input
searchInput.addEventListener("input", () => {
const inputValue = searchInput.value.trim();
// Toggle "hidden" class based on whether there is input in the search field
if (inputValue !== "") {
// Show search results container and hide page container
searchResultsContainer.classList.remove("hidden");
pageContainer.classList.add("hidden");
// Trigger Algolia search with the input value
performAlgoliaSearch(inputValue);
} else {
// Show page container and hide search results container
searchResultsContainer.classList.add("hidden");
pageContainer.classList.remove("hidden");
}
});
});