Skip to main content
A feature-rich search component with debounced input, autocomplete suggestions, search history, configurable filters, and full keyboard navigation. Perfect for building advanced search experiences.

Installation

npx shadcn@latest add https://rigidui.com/r/smart-search.json

Usage

Features

Real-time Search

Debounced search input with real-time results and visual feedback for search states.

Search History

Optional search history with local storage persistence and easy access to recent searches.

Smart Filters

Configurable filter chips and advanced query parsing with filter:value syntax support.

Keyboard Navigation

Full keyboard support with arrow keys for navigation, Enter to select, and Ctrl+/ to focus.

Autocomplete

Smart suggestion dropdown with keyboard navigation and click selection.

URL Synchronization

Optionally sync search queries with URL parameters for shareable search states.

API Reference

SmartSearch

className
string
Additional class names for styling
placeholder
string
default:"'Search...'"
Placeholder text for the search input
debounceMs
number
default:"300"
Debounce delay in milliseconds for search queries
urlSync
boolean
default:"true"
Whether to sync search query with URL parameters (?q=)
Callback function called when search query changes
searchHistory
boolean
default:"false"
Whether to enable search history functionality
suggestions
string[]
default:"[]"
Array of search suggestions to display
onSuggestionSelect
(suggestion: string) => void
Callback function called when a suggestion is selected
searchFilters
SearchFilter[]
default:"[]"
Array of filter buttons to display above the search input
interface SearchFilter {
  key: string
  label: string
  icon?: React.ReactNode
}
onFilterChange
(filters: string[]) => void
Callback function called when search filters change
resultCount
number
Number of search results to display as a badge
maxHistoryItems
number
default:"10"
Maximum number of history items to store

Examples

import { SmartSearch } from "@/components/smart-search"
import { useState } from "react"
import { FileText, Code, Book } from "lucide-react"

const filters = [
  { key: 'components', label: 'Components', icon: <Code className="w-3 h-3" /> },
  { key: 'guides', label: 'Guides', icon: <Book className="w-3 h-3" /> },
  { key: 'api', label: 'API', icon: <FileText className="w-3 h-3" /> }
]

function DocsSearch() {
  const [results, setResults] = useState([])
  const [loading, setLoading] = useState(false)

  const handleSearch = async (query: string, filters?: string[]) => {
    if (!query.trim()) {
      setResults([])
      return
    }

    setLoading(true)
    try {
      const response = await fetch(`/api/search?q=${query}&filters=${filters?.join(',')}}`)
      const data = await response.json()
      setResults(data)
    } finally {
      setLoading(false)
    }
  }

  return (
    <div>
      <SmartSearch
        placeholder="Search documentation..."
        searchFilters={filters}
        searchHistory={true}
        onSearch={handleSearch}
        resultCount={results.length}
        urlSync={true}
      />
      
      {loading && <LoadingSpinner />}
      
      <div className="mt-4 space-y-2">
        {results.map(result => (
          <SearchResult key={result.id} {...result} />
        ))}
      </div>
    </div>
  )
}
import { SmartSearch } from "@/components/smart-search"
import { Package, DollarSign, Star } from "lucide-react"

const productFilters = [
  { key: 'category', label: 'Category', icon: <Package className="w-3 h-3" /> },
  { key: 'price', label: 'Price', icon: <DollarSign className="w-3 h-3" /> },
  { key: 'rating', label: 'Top Rated', icon: <Star className="w-3 h-3" /> }
]

const popularSearches = [
  'Laptops',
  'Smartphones',
  'Headphones',
  'Cameras',
  'Smartwatches'
]

function ProductSearch() {
  const searchProducts = (query: string, filters?: string[]) => {
    // Advanced filter syntax: "category:electronics"
    const params = new URLSearchParams({
      q: query,
      filters: filters?.join(',') || ''
    })
    
    fetch(`/api/products/search?${params}`)
      .then(res => res.json())
      .then(data => displayProducts(data))
  }

  return (
    <SmartSearch
      placeholder="Search products..."
      searchFilters={productFilters}
      suggestions={popularSearches}
      searchHistory={true}
      onSearch={searchProducts}
      onSuggestionSelect={(suggestion) => {
        // Navigate to category or perform search
        router.push(`/search?q=${suggestion}`)
      }}
    />
  )
}

Advanced Search with Query Parsing

import { SmartSearch } from "@/components/smart-search"

function AdvancedSearch() {
  const handleSearch = (query: string, filters?: string[]) => {
    // Component automatically parses "author:john" syntax
    // and includes it in the filters array
    
    console.log('Query:', query) // "react tutorial"
    console.log('Filters:', filters) // ["author:john", "tag:beginner"]
    
    // Perform search with parsed filters
    performAdvancedSearch(query, filters)
  }

  return (
    <div className="space-y-4">
      <SmartSearch
        placeholder='Try "react author:john tag:beginner"'
        onSearch={handleSearch}
        debounceMs={400}
        resultCount={42}
      />
      
      <div className="text-sm text-muted-foreground">
        <p>Tip: Use filter:value syntax for advanced search</p>
        <p>Example: author:john tag:advanced category:tutorial</p>
      </div>
    </div>
  )
}

Command Palette Style

import { SmartSearch } from "@/components/smart-search"
import { useEffect } from "react"

function CommandPalette() {
  useEffect(() => {
    // Focus search on Ctrl+/
    const handleKeyDown = (e: KeyboardEvent) => {
      if ((e.ctrlKey || e.metaKey) && e.key === '/') {
        e.preventDefault()
        // Focus is handled by SmartSearch internally
      }
    }

    document.addEventListener('keydown', handleKeyDown)
    return () => document.removeEventListener('keydown', handleKeyDown)
  }, [])

  return (
    <div className="fixed top-4 left-1/2 -translate-x-1/2 w-full max-w-2xl px-4">
      <SmartSearch
        placeholder="Search or jump to..."
        suggestions={[
          'Go to Dashboard',
          'Open Settings',
          'View Profile',
          'Create New Project'
        ]}
        searchHistory={true}
        onSuggestionSelect={(suggestion) => {
          // Navigate based on suggestion
          handleNavigation(suggestion)
        }}
        className="shadow-2xl"
      />
    </div>
  )
}
The component supports advanced query syntax like filter:value. For example, searching “react author:john” will automatically parse the filter and pass it separately to your onSearch callback.
Search history is automatically saved to localStorage with the key smart-search-history. The component handles all storage operations internally.
Keyboard shortcuts:
  • ↑/↓: Navigate through suggestions
  • Enter: Select highlighted suggestion or perform search
  • Escape: Close suggestions and blur input
  • Ctrl+/: Focus search input (built-in)

Build docs developers (and LLMs) love