npm package: @findable-ai/react
Description: React components and hooks for the Findable Partner API
Latest version: 0.2.4

# @findable-ai/react

Drop-in React components and headless hooks for the [Findable](https://findable.ai) Partner API. Five lines to a working AI chat in your app.

[![npm version](https://img.shields.io/npm/v/@findable-ai/react)](https://www.npmjs.com/package/@findable-ai/react)

> **Full documentation**: [docs.findable.dev](https://docs.findable.dev/react)

## Installation

```bash
npm install @findable-ai/react
```

## Quick start

```tsx
import { FindableProvider, FindableChat } from '@findable-ai/react';
import '@findable-ai/react/styles.css';

function App() {
  return (
    <FindableProvider apiKey="YOUR_API_KEY" buildingOwnerId="YOUR_BUILDING_OWNER_ID">
      <FindableChat buildingId="bld-789" />
    </FindableProvider>
  );
}
```

That's it — a fully working chat widget with streaming responses, citations, and follow-up suggestions.

## Components

### `<FindableChat>`

Full-featured chat widget with message history, streaming, citations, and follow-up suggestions.

```tsx
<FindableChat
  buildingId="bld-789"
  placeholder="Ask about your building..."
  title="Ask Findable"
  language="en"
  reasoningEffort="medium"
  showCitations={true}
  showFollowUps={true}
  className="my-chat"
  onError={(err) => console.error(err)}
  onThreadCreated={(threadId) => saveThreadId(threadId)}
  onCitationClick={(citation) => openDocument(citation.documentId)}
  renderMessage={(msg) => <CustomMessage {...msg} />}
/>
```

| Prop              | Type                                    | Default                        | Description                          |
| ----------------- | --------------------------------------- | ------------------------------ | ------------------------------------ |
| `buildingId`      | `string`                                | _required_                     | Building to query                    |
| `placeholder`     | `string`                                | `"Ask about your building..."` | Input placeholder                    |
| `title`           | `string`                                | `"Ask Findable"`               | Header title (empty string hides it) |
| `language`        | `'en' \| 'no' \| 'nb' \| 'nn'`          | —                              | Response language                    |
| `reasoningEffort` | `'low' \| 'medium' \| 'high'`           | —                              | AI reasoning effort                  |
| `showCitations`   | `boolean`                               | `true`                         | Show inline citation badges          |
| `showFollowUps`   | `boolean`                               | `true`                         | Show follow-up suggestion chips      |
| `className`       | `string`                                | —                              | Additional CSS class                 |
| `onError`         | `(error: Error) => void`                | —                              | Error callback                       |
| `onThreadCreated` | `(threadId: string) => void`            | —                              | New thread callback                  |
| `onCitationClick` | `(citation: AskCitation) => void`       | —                              | Citation click handler               |
| `renderMessage`   | `(message: ChatMessage) => JSX.Element` | —                              | Custom message renderer              |

### `<FindableSearch>`

Document search with debounced input, results list, and pagination.

```tsx
<FindableSearch
  buildingId="bld-789"
  placeholder="Search documents..."
  maxResults={10}
  debounceMs={300}
  className="my-search"
  onHitClick={(hit) => window.open(`/docs/${hit.id}`)}
  renderHit={(hit) => <CustomHit {...hit} />}
/>
```

| Prop          | Type                              | Default                 | Description                       |
| ------------- | --------------------------------- | ----------------------- | --------------------------------- |
| `buildingId`  | `string`                          | —                       | Building to search (omit for all) |
| `placeholder` | `string`                          | `"Search documents..."` | Input placeholder                 |
| `maxResults`  | `number`                          | `10`                    | Results per page                  |
| `debounceMs`  | `number`                          | `300`                   | Input debounce delay              |
| `className`   | `string`                          | —                       | Additional CSS class              |
| `onHitClick`  | `(hit: SearchHit) => void`        | —                       | Result click handler              |
| `onError`     | `(error: Error) => void`          | —                       | Error callback                    |
| `renderHit`   | `(hit: SearchHit) => JSX.Element` | —                       | Custom result renderer            |

## Headless hooks

For complete control over the UI, use the hooks directly:

### `useChat`

```typescript
import { useChat } from '@findable-ai/react';

function MyChat() {
  const { messages, status, followUpSuggestions, sendMessage, cancelStream, clearChat, threadId } =
    useChat({ buildingId: 'bld-789' });

  return (
    <div>
      {messages.map((msg) => (
        <div key={msg.id} className={msg.role}>
          {msg.content}
        </div>
      ))}
      <button onClick={() => sendMessage('What are the fire safety docs?')}>Ask</button>
    </div>
  );
}
```

### `useSearch`

```typescript
import { useSearch } from '@findable-ai/react';

function MySearch() {
  const { results, totalHits, isLoading, error, search, loadMore, clear } =
    useSearch({ buildingId: 'bld-789' });

  return (
    <div>
      <input onChange={(e) => search(e.target.value)} />
      {results.map((hit) => (
        <div key={hit.id}>{hit.filename}</div>
      ))}
      {results.length < totalHits && <button onClick={loadMore}>Load more</button>}
    </div>
  );
}
```

## Theming

Import the default styles and override CSS custom properties:

```css
@import '@findable-ai/react/styles.css';

.findable-root {
  --findable-color-primary: #e63946;
  --findable-color-bg: #ffffff;
  --findable-color-text: #1a1a1a;
  --findable-font-family: 'Inter', sans-serif;
  --findable-radius-md: 12px;
  --findable-chat-height: 500px;
}
```

See the full list of CSS custom properties in the [theming guide](https://docs.findable.dev/react/theming).

## SDK access

The underlying `FindableClient` is available for direct API calls:

```typescript
import { useFindableClient } from '@findable-ai/react';

function MyComponent() {
  const client = useFindableClient();
  // Use client.ask(), client.search(), client.listBuildings(), etc.
}
```

## Documentation

- [Getting started](https://docs.findable.dev/getting-started)
- [Chat component](https://docs.findable.dev/react/chat)
- [Search component](https://docs.findable.dev/react/search)
- [Theming guide](https://docs.findable.dev/react/theming)
- [SDK reference](https://docs.findable.dev/sdk)
- [API reference](https://docs.findable.dev/api)

## Licence

MIT