React Integration

Last updated:

Add search to your React app in under 5 minutes with @lumosearch/react.

Installation

npm install @lumosearch/react

Quick Start

Import the component and default styles, then drop it into your page:

import { LumoSearchBox } from '@lumosearch/react'
import '@lumosearch/react/styles.css'

function SearchPage() {
  return (
    <LumoSearchBox
      publicKey="pk_search_..."
      collection="products"
      placeholder="Search products..."
      onSelect={(result) => {
        // Navigate to the result
        window.location.href = `/products/${result.item.id}`
      }}
    />
  )
}

That's it. You get debounced search, keyboard navigation, highlighted matches, and a loading spinner out of the box.

Using the Provider

If you have multiple search boxes or want to share configuration, wrap your app with LumoSearchProvider:

import { LumoSearchProvider, LumoSearchBox } from '@lumosearch/react'
import '@lumosearch/react/styles.css'

function App() {
  return (
    <LumoSearchProvider config={{
      publicKey: "pk_search_...",
      collection: "products",
    }}>
      <Navbar />
      <MainContent />
    </LumoSearchProvider>
  )
}

// Any child can use LumoSearchBox without repeating config
function Navbar() {
  return <LumoSearchBox placeholder="Quick search..." limit={5} />
}

Autocomplete Mode

Switch to the autocomplete endpoint for faster prefix-based suggestions:

<LumoSearchBox
  publicKey="pk_search_..."
  collection="products"
  autocomplete={true}
  debounceMs={150}
  limit={5}
/>

Custom Result Rendering

Use renderResult to fully customize how each result looks:

<LumoSearchBox
  publicKey="pk_search_..."
  collection="products"
  titleField="name"
  descriptionField="description"
  renderResult={(result, highlighted) => (
    <div className="flex items-center gap-3 p-2">
      <img
        src={result.item.image as string}
        className="w-10 h-10 rounded object-cover"
      />
      <div>
        <div className="font-medium">{highlighted}</div>
        <div className="text-sm text-gray-500">
          ${result.item.price}
        </div>
      </div>
    </div>
  )}
/>

Custom Styling

You can either import the default CSS or use className props for full control (works great with Tailwind):

// Option 1: Default styles
import '@lumosearch/react/styles.css'

// Option 2: Tailwind classes
<LumoSearchBox
  inputClassName="w-full rounded-lg border border-gray-200 px-4 py-3 focus:ring-2 focus:ring-blue-500"
  resultsClassName="absolute mt-1 w-full rounded-lg border shadow-lg bg-white"
  resultClassName="px-4 py-2 hover:bg-gray-50 cursor-pointer"
/>

Keyboard Navigation

Built-in keyboard support — no configuration needed:

  • ↓ / ↑ — Navigate through results
  • Enter — Select the highlighted result (triggers onSelect)
  • Escape — Close the dropdown

Props Reference

PropTypeDefaultDescription
publicKeystringPublic search API key
collectionstringCollection slug or ID
apiUrlstringapi.lumosearch.comAPI host URL
placeholderstring"Search..."Input placeholder
debounceMsnumber250Debounce delay in ms
limitnumber8Max results
autocompletebooleanfalseUse autocomplete endpoint
onSelect(result) => voidCalled on result selection
titleFieldstringautoField for result title
descriptionFieldstringField for description
renderResult(result, highlighted) => ReactNodeCustom result renderer
showResponseTimebooleantrueShow timing badge
autoFocusbooleanfalseFocus input on mount

Next.js App Router

The component is a client component. In Next.js App Router, use it in a client component or add "use client" at the top of the file:

"use client"

import { LumoSearchBox } from '@lumosearch/react'
import '@lumosearch/react/styles.css'

export function SearchWidget() {
  return (
    <LumoSearchBox
      publicKey={process.env.NEXT_PUBLIC_LUMO_KEY!}
      collection="docs"
      placeholder="Search docs..."
    />
  )
}

TypeScript

Full TypeScript types are included. Import types for custom integrations:

import type { LumoSearchResult, LumoSearchBoxProps } from '@lumosearch/react'

function handleSelect(result: LumoSearchResult) {
  const product = result.item as { id: string; name: string; price: number }
  router.push(`/products/${product.id}`)
}