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
| Prop | Type | Default | Description |
|---|---|---|---|
| publicKey | string | — | Public search API key |
| collection | string | — | Collection slug or ID |
| apiUrl | string | api.lumosearch.com | API host URL |
| placeholder | string | "Search..." | Input placeholder |
| debounceMs | number | 250 | Debounce delay in ms |
| limit | number | 8 | Max results |
| autocomplete | boolean | false | Use autocomplete endpoint |
| onSelect | (result) => void | — | Called on result selection |
| titleField | string | auto | Field for result title |
| descriptionField | string | — | Field for description |
| renderResult | (result, highlighted) => ReactNode | — | Custom result renderer |
| showResponseTime | boolean | true | Show timing badge |
| autoFocus | boolean | false | Focus 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}`)
}