6 min read
The Nightmare Feature: Implementing Search
Written by
Abdul Rafay
During my time as a developer, one feature consistently stands out as particularly challenging to set up: search. What makes search tricky is that it varies not only from project to project but even across static sites. Thankfully, modern web development uses frameworks that streamline full-stack application development, and many of these projects are based on React or React-based frameworks.
Search is a critical feature for any website. It ensures that users can find the content they’re looking for. If the search functionality is ineffective, it becomes useless. But how do you set up a search feature that works well? Let’s dive into it.
What is React?
Before we delve into the search implementation, let’s first understand React and JavaScript, and how they can help us create a search feature on a site.
React is a JavaScript library developed by Meta (formerly Facebook). It’s a UI library that enables developers to build dynamic and interactive user interfaces using JavaScript and Node.js. React simplifies the process of creating visually appealing websites with reusable components.
Getting Started
Now that we have a basic understanding of React, let’s go over how to create a search feature. First, you’ll need some content on your site. For this example, I’m using Astro—a modern static site generator optimized for content-driven sites. I have a lot of content written in Markdown, and I build my website using the Astro framework.
Astro is a JavaScript framework like React, but it’s specifically designed to make content-driven websites easier and faster to build.
Creating an Astro Project
To create an Astro project, enter the following command:
npm create astro@latest
This command will guide you through some setup questions. Answer them, and you’ll have a working Astro project. I recommend starting with the Blog template, as it provides many pre-configured features that simplify your development process. For more information, check out Astro’s official documentation.
Enabling React
Once you have your Astro site set up, the next step is to enable React. The reason we’re using React is that it allows us to create clean and customizable UI components, and with the help of packages like Fuzzy, we can implement a powerful search feature.
To enable React in your Astro project, run the following command:
npx astro add react
This will automatically integrate React into your Astro site. If you prefer manual setup, you can refer to this guide.
Creating Components
Now, it’s time to create components for both your Astro and React projects. The file structure for my project looks like this:
src
├── components
│ ├── BaseHead.astro
│ ├── Footer.astro
│ ├── FormattedDate.astro
│ ├── Header.astro
│ ├── HeaderLink.astro
│ └── react
│ ├── SearchComponent.tsx
│ └── SearchComponentLogic.tsx
└── content
├── config.ts
└── blog
├── first-post.md
├── markdown-style-guide.md
├── second-post.md
├── third-post.md
└── using-mdx.mdx
In the structure above, I created two files: SearchComponent.tsx
for the UI and SearchComponentLogic.tsx
for the logic. This approach separates the search functionality into the user interface (UI) and the underlying logic, making the code more organized.
Fuzzy Search
To make the search functionality work, we’ll use a package called Fuzzy. Fuzzy search allows for flexible and tolerant search functionality by matching user input with relevant content, even if the match isn’t exact.
Application Logic
The search logic is straightforward. Astro has a content layer, and we can pass data from this layer throughout the project. Using this capability, we can build a robust search feature.
All the blog data will be passed into the React component (SearchData
), and Fuzzy will index this data. When the user enters a query, Fuzzy will search through the indexed data and return the results. The React component will then display the matching results in a user-friendly manner.
Why React?
This approach is highly customizable and provides superior performance compared to JavaScript functions that crawl through the entire site. React allows us to build a better UI while keeping the search fast and efficient.
For example, on my site, the search feature looks through multiple fields—author names, blog post content, titles, and even publication dates. This makes it highly adaptable to different needs.
Code Breakdown
Let’s walk through the code that powers this search feature.
Search UI Component
Imports
- React: The core library for building UI components in JavaScript.
- useSearchablePosts: A custom hook (explained later) that manages search logic, including state for the query and filtered posts.
Post Interface
interface Post {
id: string;
slug: string;
body: string;
collection: string;
data: {
title: string;
description: string;
pubDate: Date;
updatedDate?: Date;
heroImage?: string;
};
}
This interface defines the structure of a blog post, including metadata such as the title, description, and publication date.
SearchablePostsProps Interface
interface SearchablePostsProps {
posts: Post[];
}
This interface describes the props passed to the SearchablePosts
component, which expects an array of Post
objects.
SearchablePostsUI Component
const SearchablePostsUI: React.FC<{
query: string;
filteredPosts: Post[];
handleSearch: (e: React.ChangeEvent<HTMLInputElement>) => void;
}> = ({ query, filteredPosts, handleSearch }) => {
// UI rendering logic here...
};
This component handles the user interface for the search feature. It displays a search input field and a list of filtered posts based on the user’s query.
Search Logic Component
The logic behind the search functionality is handled by a custom hook called useSearchablePosts
. Here’s a brief overview:
State Management
const [query, setQuery] = useState<string>("");
const [filteredPosts, setFilteredPosts] = useState<Post[]>([]);
These states track the user’s query and the list of posts that match the search.
Search Handler
const handleSearch = (e: ChangeEvent<HTMLInputElement>) => {
const searchQuery = e.target.value;
setQuery(searchQuery);
// Fuzzy search logic here...
};
This function is triggered whenever the user types in the search box, updating the search query and filtering the posts using Fuzzy search.
Search Logic
const results = fuzzy.filter(searchQuery, posts, {
extract: (el: Post) => el.data.title,
});
const matches = results.map((result) => result.original);
setFilteredPosts(matches);
The Fuzzy search library is used to match the user’s input with the post titles and return the relevant results.
Custom Hook Return
return { query, filteredPosts, handleSearch };
The hook returns the current query, filtered posts, and the search handler, which are used in the UI component.
Since you are using MDX, we can make your blog post more interactive by embedding code snippets and creating collapsible sections or even interactive components. Here’s an idea of how you can make your GitHub project section more engaging and interactive:
Search Feature Code
I’ve implemented the search functionality in an Astro project, and you can explore the full code on GitHub. Below is an interactive code snippet for the setup. You can collapse sections to focus on specific areas or expand them to dive deeper into the code logic.
GitHub Project:
Check out the full project on GitHub
Conclusion
By combining Astro and React, we’ve built a customizable, efficient, and scalable search feature that adapts to various needs. This approach leverages React’s component-based architecture and Fuzzy’s flexible search capabilities to deliver a fast and user-friendly experience.