# Search components

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

`Search` renders the search bar and, while a search is open, its results: channels, users and messages. It reads the `SearchController` that [`Chat`](https://getstream.io/chat/docs/sdk/react/v15/component-reference/chat/chat/) provides, so it works anywhere inside `Chat`. `ChannelNavigation` renders it above the channel lists. [Search](https://getstream.io/chat/docs/sdk/react/v15/features/channels/search/) explains the feature, and [Search sources](https://getstream.io/chat/docs/sdk/react/v15/state/loading-data/search-sources/) the controller and its sources.

## Best practices

- Change what is searched on the controller and its sources, not in the components. Pass your own controller to `Chat` as `searchController`.
- Create your own controller once per client, for example with `useMemo`. A new controller on every render starts every search from scratch.
- Replace one part of the search UI with its override key rather than the whole `Search`.
- To set `Search` props on the `Search` that `ChannelNavigation` renders, register a component that renders `Search` with them under the `Search` key.

## Basic usage

```tsx
import type { PropsWithChildren } from "react";
import { Search, WithComponents } from "stream-chat-react";

const SidebarSearch = () => (
  <Search exitSearchOnInputBlur placeholder="Search chats and people" />
);

const overrides = { Search: SidebarSearch };

export const WithSidebarSearch = ({ children }: PropsWithChildren) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);
```

Rendered around `ChannelNavigation`, this replaces the search bar above the lists. Outside `ChannelNavigation`, render `<Search />` wherever the layout needs it.

`Search` props:

| Prop                         | Type                                      | Default       | Description                                                                                                                                                                                            |
| ---------------------------- | ----------------------------------------- | ------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| `directMessagingChannelType` | `string`                                  | `"messaging"` | The channel type of the direct message channel a user result opens.                                                                                                                                    |
| `disabled`                   | `boolean`                                 | `false`       | Disables the input.                                                                                                                                                                                    |
| `exitSearchOnInputBlur`      | `boolean`                                 | `false`       | Closes search when focus leaves the search bar and its results.                                                                                                                                        |
| `inputProps`                 | `React.ComponentPropsWithoutRef<"input">` | none          | Props for the `<input>`, such as `name` or `autoComplete`. The input's own `value`, `onChange`, `onBlur`, `type`, `disabled`, `placeholder` and `aria-label` win; `className` is added to the default. |
| `placeholder`                | `string`                                  | "Search"      | The placeholder of the input.                                                                                                                                                                          |

Typing opens search and passes the text to the controller. The clear button empties the text. Cancel, or the Escape key, closes search.

## Anatomy

`Search` provides `SearchContext` and renders `SearchBar` and `SearchResults`. Each part is read from an override key:

| Override key                          | Renders                                                                                                                       | Gets                          |
| ------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------- | ----------------------------- |
| `SearchBar`                           | The input, the clear button, and Cancel while search is open                                                                  | nothing                       |
| `SearchResults`                       | Nothing while search is closed. Otherwise the header, then the presearch state or one `SearchSourceResults` per active source | nothing                       |
| `SearchResultsHeader`                 | The buttons that choose the source. Nothing when the controller has fewer than two sources                                    | nothing                       |
| `SearchResultsPresearch`              | "Start typing to search", while the text is empty                                                                             | `activeSources`               |
| `SearchSourceResults`                 | One source's results, inside `SearchSourceResultsContext`. Nothing before the source's first search                           | `searchSource`                |
| `SearchSourceResultsHeader`           | Nothing by default. Renders above a source's results                                                                          | nothing                       |
| `SearchSourceResultList`              | The results in an infinite scroll, then `SearchSourceResultListFooter`                                                        | [Below](#custom-result-items) |
| `SearchSourceResultListFooter`        | `SearchSourceResultsLoadingIndicator` while loading, "All results loaded" when there are no more                              | nothing                       |
| `SearchSourceResultsLoadingIndicator` | "Searching for" and the source's type, such as "Searching for users..."                                                       | nothing                       |
| `SearchSourceResultsEmpty`            | "No results found", when a source found nothing                                                                               | nothing                       |

## UI customization

Register replacements with `WithComponents`. The default of every key above except `SearchSourceResultsHeader`, which renders nothing, is exported under the same name, so a replacement can render the default with something added:

```tsx
import type { PropsWithChildren } from "react";
import { SearchSourceResultsEmpty, WithComponents } from "stream-chat-react";

const EmptyWithHint = () => (
  <div className="search-empty">
    <SearchSourceResultsEmpty />
    <p>Try a shorter word, or search messages instead.</p>
  </div>
);

const overrides = { SearchSourceResultsEmpty: EmptyWithHint };

export const WithSearchHint = ({ children }: PropsWithChildren) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);
```

A part reads the controller with `useSearchContext()`, and the source it renders with `useSearchSourceResultsContext()`. [Reading search state in your own components](https://getstream.io/chat/docs/sdk/react/v15/features/channels/search/#reading-search-state-in-your-own-components) has an example. To remove search from `ChannelNavigation`, register a `Search` that renders nothing.

## Custom result items

`SearchSourceResultList` props:

| Prop                  | Type                                           | Default                    | Description                                                                                      |
| --------------------- | ---------------------------------------------- | -------------------------- | ------------------------------------------------------------------------------------------------ |
| `SearchResultItems`   | `Record<string, ComponentType<{ item: any }>>` | `DefaultSearchResultItems` | The component for one result, by the source's `type`. A source with no entry renders no results. |
| `loadMoreDebounceMs`  | `number`                                       | `100`                      | How long the list waits after the user stops scrolling before it checks whether to load more.    |
| `loadMoreThresholdPx` | `number`                                       | `80`                       | How close to the end, in pixels, scrolling has to come to load more.                             |

`DefaultSearchResultItems` maps the built-in sources to their result components:

| Source type | Component                 | `item`            | Click                                                    |
| ----------- | ------------------------- | ----------------- | -------------------------------------------------------- |
| `channels`  | `ChannelSearchResultItem` | `Channel`         | Opens the channel and adds it to the lists it belongs to |
| `messages`  | `MessageSearchResultItem` | `MessageResponse` | Opens the message's channel and jumps to the message     |
| `users`     | `UserSearchResultItem`    | `UserResponse`    | Opens the direct message channel with the user           |

Each component also takes `onSelect: (event: React.MouseEvent) => void`, which runs instead of the default click. To replace one, start from `DefaultSearchResultItems`:

```tsx
import type { PropsWithChildren } from "react";
import type { UserResponse } from "stream-chat";
import {
  DefaultSearchResultItems,
  SearchSourceResultList,
  WithComponents,
} from "stream-chat-react";

const InviteUserResult = ({ item }: { item: UserResponse }) => (
  <button className="invite-result" type="button">
    Invite {item.name ?? item.id}
  </button>
);

const ResultList = () => (
  <SearchSourceResultList
    SearchResultItems={{ ...DefaultSearchResultItems, users: InviteUserResult }}
  />
);

const overrides = { SearchSourceResultList: ResultList };

export const WithInviteResults = ({ children }: PropsWithChildren) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);
```

A source of your own needs an entry under its `type`; see [Searching your own data](https://getstream.io/chat/docs/sdk/react/v15/features/channels/search/#searching-your-own-data).

## Data management

The data comes from the controller. `Chat` creates one with `ChannelSearchSource`, `UserSearchSource` and `MessageSearchSource` when the app doesn't pass `searchController`. To change what is searched, pass your own; [Choosing what to search](https://getstream.io/chat/docs/sdk/react/v15/features/channels/search/#choosing-what-to-search) shows how, and [Search sources](https://getstream.io/chat/docs/sdk/react/v15/state/loading-data/search-sources/) explains the sources, their filters and their state.

The two search contexts hold:

| Context                      | Hook                              | Values                                                                                                                                                                                       |
| ---------------------------- | --------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `SearchContext`              | `useSearchContext()`              | `searchController`; `containerRef` and `filterButtonsContainerRef`; and the `Search` props `directMessagingChannelType`, `disabled`, `exitSearchOnInputBlur`, `inputProps` and `placeholder` |
| `SearchSourceResultsContext` | `useSearchSourceResultsContext()` | `searchSource`, the source whose results are rendered                                                                                                                                        |

Both hooks throw outside their component. [Loading data hooks](https://getstream.io/chat/docs/sdk/react/v15/reference/hooks/loading-data-hooks/#usesearchcontext) has their details.

### Typing the context of `MessageSearchSource`

`MessageSearchSource` builds three filters, each with a filter builder of its own:

- `messageSearchChannelFilterBuilder`: which channels to search in;
- `messageSearchFilterBuilder`: which messages to return;
- `channelQueryFilterBuilder`: which channels of the results to load.

Each builder can carry a context of your own, and the source's type parameter names them, one key per builder: `messageSearchChannelContext`, `messageSearchContext` and `channelQueryContext`. The third constructor argument configures the builders under `messageSearchChannel`, `messageSearch` and `channelQuery`. This source can limit the results to pinned messages:

```ts
import { MessageSearchSource } from "stream-chat";

const messageSource = new MessageSearchSource<{
  messageSearchContext: { onlyPinned: boolean };
}>(client, undefined, {
  messageSearch: {
    initialContext: { onlyPinned: false },
    initialFilterConfig: {
      pinned: {
        enabled: true,
        generate: ({ onlyPinned }) =>
          onlyPinned ? { pinned: { $eq: true } } : null,
      },
    },
  },
});

// later, from a toggle in the results header
messageSource.messageSearchFilterBuilder.updateContext({ onlyPinned: true });
```

Each builder's context also holds what the source sets itself: `searchQuery` for the first two, and `cids`, the channels to load, for the third. The source keeps its built-in generators for the message text and the channels to load, and adds yours. The new context applies from the next query.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v15/component-reference/channel-list/search-components/](https://getstream.io/chat/docs/sdk/react/v15/component-reference/channel-list/search-components/).