Setup
Start with <Searchbar />. It is the fastest path for most apps.
Move to primitives only when you need custom UI.

1) Drop-in Searchbar
"use client";
import { useRouter } from "next/navigation";
import "@etoile-dev/react/styles.css";
import { Searchbar } from "@etoile-dev/react";
export default function App() {
const router = useRouter();
return (
<Searchbar
apiKey={process.env.NEXT_PUBLIC_ETOILE_PUBLIC_KEY}
collections={["paintings", "artists"]}
onSelectResult={(result) => router.push(`/work/${result.external_id}`)}
/>
);
}Use your public key in client-side React code.
2) Command palette
"use client";
import { useRouter } from "next/navigation";
import "@etoile-dev/react/styles.css";
import { SearchModal } from "@etoile-dev/react";
export default function App() {
const router = useRouter();
return (
<SearchModal
apiKey={process.env.NEXT_PUBLIC_ETOILE_PUBLIC_KEY}
collections={["paintings", "artists"]}
onSelectResult={(result) => router.push(`/work/${result.external_id}`)}
/>
);
}3) Headless primitives
Use primitives when you want full control over markup and styles.
Searchbar.Results keeps the result mapping simple.
"use client";
import { useState } from "react";
import { Searchbar, useEtoileSearch } from "@etoile-dev/react";
export default function CustomSearch() {
const [query, setQuery] = useState("");
const { results, isLoading, error } = useEtoileSearch({
apiKey: process.env.NEXT_PUBLIC_ETOILE_PUBLIC_KEY,
collections: ["paintings", "artists"],
query,
});
return (
<Searchbar.Root
search={query}
onSearchChange={setQuery}
isLoading={isLoading}
error={error}
>
<Searchbar.Input placeholder="Search..." />
<Searchbar.List>
<Searchbar.Results
results={results}
renderItem={(result) => (
<Searchbar.Item value={result.external_id} label={result.title}>
{result.title}
</Searchbar.Item>
)}
/>
</Searchbar.List>
</Searchbar.Root>
);
}Searchbar props
| Parameter | Type | Description |
|---|---|---|
apiKeyrequired | string | Your public API key. |
collectionsrequired | string[] | Collections to search. |
limit | number | Max results (default: 10). |
offset | number | Pagination offset (default: 0). |
debounceMs | number | Debounce delay in ms (default: 100). |
placeholder | string | Input placeholder (default: "Search…"). |
filters | SearchFilter[] | Apply explicit metadata filters. |
autoFilters | boolean | Let AI extract filters from the query. |
renderItem | (result: SearchResult) => ReactNode | Custom item renderer. |
onSelect | (value: string) => void | Called with selected external_id. |
onSelectResult | (result: SearchResult) => void | Called with the full selected result. Recommended for routing. |
hotkey | string | Global shortcut, for example "/" or "mod+k". |
className | string | Extra class names. The wrapper always includes "etoile-search". |
Searchbar also supports non-state behavior props from Searchbar.Root, such as open, defaultOpen, onOpenChange, and hotkeyBehavior.
Resources
Next
- Styling — default theme and custom UI
- Hooks —
useEtoileSearchreference - Search (POST) — API reference