DEV Community

Cover image for 🚀 Building Lightning-Fast Search with search-plus-ts: A Full-Stack TypeScript Solution
Dev Gaurav Jatt
Dev Gaurav Jatt

Posted on

🚀 Building Lightning-Fast Search with search-plus-ts: A Full-Stack TypeScript Solution

Building modern search experiences shouldn't be rocket science. Let me show you how to create a blazing-fast, real-time search system using TypeScript, Hono, and React.

The Problem

Ever tried implementing search functionality and ended up with a sluggish, overcomplicated mess? You're not alone. Most developers either:

  • Over-engineer with complex search engines like Elasticsearch
  • Under-deliver with basic string matching that feels broken
  • Get lost in the complexity of fuzzy search algorithms

What if I told you there's a sweet spot? A TypeScript-first solution that's both powerful and simple?

Meet search-plus-ts

search-plus-ts is a lightweight, TypeScript-native search library that brings intelligent search capabilities without the overhead. Today, I'll walk you through building a complete full-stack search application using:

  • Backend: Hono (the fast, lightweight web framework)
  • Frontend: React with Vite
  • Search Engine: search-plus-ts
  • Styling: Tailwind CSS

🎯 What We're Building

A real-time search interface for blog posts that features:

  • ⚡ Instant search results as you type
  • 🎨 Highlighted search matches
  • 🔍 Multi-field searching (title, category, date)
  • 📱 Responsive design
  • 🚀 TypeScript throughout

Setting Up the Backend

Let's start with our Hono server. First, the data structure:

// hono-server/src/data.ts
const posts = [
  {
    title: 'Copyleaks Study Finds Explosive Growth of AI Content on the Web',
    categorie: 'Artificial Intelligence',
    date: 'May 1st 2024, 5:00:46 am',
  },
  {
    title: 'Musk\'s YouTube-Like TV Venture Faces Strong Challenges From Incumbents',
    categorie: 'Online Entertainment',
    date: 'March 12th 2024, 5:00:59 am',
  },
  // ... more posts
]

export default posts
Enter fullscreen mode Exit fullscreen mode

Now, the server implementation:

// hono-server/src/index.ts
import { serve } from '@hono/node-server'
import { Hono } from 'hono'
import SearchPlusTs from 'search-plus-ts'
import posts from './data.js'
import { cors } from 'hono/cors'

const app = new Hono()
app.use(cors())

// Get all posts
app.get('/', (c) => {
  return c.json({ posts })
})

// Search endpoint - this is where the magic happens
app.get('/search', (c) => {
  const search = c.req.query().q
  if (!search) {
    return c.json({ posts: [] })
  }

  const SearchPlus = new SearchPlusTs({
    data: posts,
    keys: ['title', 'categorie', 'date'], // Fields to search
  })

  const results = SearchPlus.search(search)
  return c.json({ results })
})

serve({ fetch: app.fetch, port: 3000 }, (info) => {
  console.log(`Server is running on http://localhost:${info.port}`)
})
Enter fullscreen mode Exit fullscreen mode

Building the React Frontend

The frontend is where users interact with our search. Here's the complete component:

// vite-react-client/src/App.tsx
import { useEffect, useState } from 'react'
import { highlightWordsTag } from 'search-plus-ts'

const App: React.FC = () => {
  const [query, setQuery] = useState('')
  const [posts, setPosts] = useState<{
    title: string
    categorie: string
    date: string
  }[]>([])

  useEffect(() => {
    if (query.trim() !== '') {
      fetch('http://localhost:3000/search?q=' + query)
        .then((res) => res.json())
        .then((data) => setPosts(data.results))
    } else {
      fetch('http://localhost:3000')
        .then((res) => res.json())
        .then((data) => setPosts(data.posts))
    }
  }, [query])

  return (
    <div className='max-w-3xl mx-auto p-6'>
      <input
        type='search'
        value={query}
        onChange={(e) => setQuery(e.target.value)}
        placeholder='Search posts...'
        className='w-full p-3 border border-stone-300 rounded-xl focus:outline-none focus:ring-2 focus:ring-orange-500 mb-6 shadow-sm transition-all'
      />

      {posts.length === 0 ? (
        <p className='text-center text-stone-500 mt-10'>No results found.</p>
      ) : (
        posts.map((post, id) => (
          <div
            key={id}
            className='mb-6 p-6 bg-white hover:bg-stone-50 transition-colors duration-200 border border-stone-200 rounded-2xl shadow-sm'
          >
            <div className='text-xl font-bold text-stone-800 mb-2'>
              <span className='text-orange-600'>Title:</span>{' '}
              <span
                dangerouslySetInnerHTML={{
                  __html: highlightWordsTag(post.title, query, 'search-match'),
                }}
              />
            </div>

            <div className='flex justify-between items-center'>
              <div className='text-sm text-stone-600'>
                <span className='font-semibold text-orange-500'>Category:</span>{' '}
                <span
                  dangerouslySetInnerHTML={{
                    __html: highlightWordsTag(post.categorie, query, 'search-match'),
                  }}
                />
              </div>
              <div className='text-sm text-stone-600'>
                <span className='font-semibold text-orange-500'>Date:</span>{' '}
                <span
                  dangerouslySetInnerHTML={{
                    __html: highlightWordsTag(post.date, query, 'search-match'),
                  }}
                />
              </div>
            </div>
          </div>
        ))
      )}
    </div>
  )
}

export default App
Enter fullscreen mode Exit fullscreen mode

The Secret Sauce: Highlighting Matches

Notice the highlightWordsTag function? This is what makes search results feel professional:

/* vite-react-client/src/index.css */
@import 'tailwindcss';

.search-match {
  @apply bg-yellow-300 font-semibold px-1;
}
Enter fullscreen mode Exit fullscreen mode

This CSS class automatically highlights matching text in search results, creating that satisfying "Google-like" experience users expect.

Running the Application

The beauty of this setup is its simplicity. Just run:

# Clone the example
npx gitpick https://github.com/devgauravjatt/search-plus-ts/examples/with-server-and-client

cd with-server-and-client

# Install dependencies
npm install

# Start both server and client
npm run dev
Enter fullscreen mode Exit fullscreen mode

The monorepo setup with workspaces means everything runs concurrently - your backend API at localhost:3000 and your React app at localhost:5173.

Why This Architecture Works

🎯 Separation of Concerns

  • Server handles search logic and data
  • Client focuses purely on UI/UX
  • Clean API contract between layers

Performance

  • search-plus-ts is optimized for speed
  • Hono is one of the fastest web frameworks
  • React's virtual DOM handles UI updates efficiently

🔧 Developer Experience

  • Full TypeScript support throughout
  • Hot reload on both ends
  • Simple, predictable data flow

📈 Scalability

  • Easy to add more search fields
  • Simple to extend with filters
  • Straightforward to optimize further

Real-World Applications

This pattern works great for:

  • Documentation sites with search
  • E-commerce product filtering
  • Blog platforms with post search
  • Admin dashboards with data lookup
  • Content management systems

Advanced Features You Can Add

Want to take this further? Consider adding:

  1. Debounced search to reduce API calls
  2. Search suggestions and autocomplete
  3. Filter by category or date ranges
  4. Pagination for large datasets
  5. Search analytics and popular queries

Key Takeaways

Building great search doesn't require complex infrastructure. With the right tools:

  • search-plus-ts handles the intelligent matching
  • Hono provides a fast, modern backend
  • React delivers smooth user interactions
  • TypeScript keeps everything type-safe

The result? A search experience that feels instant, looks professional, and scales with your needs.

Try It Yourself

Ready to build your own search-powered application?

🔗 Get the complete code

🚀 Check out search-plus-ts


What kind of search features are you planning to build? Let me know in the comments below! 👇


Top comments (0)

Some comments may only be visible to logged-in visitors. Sign in to view all comments.