# Entry points and native handlers

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

An app built with React Native CLI imports its components from `stream-chat-react-native`. An Expo app imports the same components from `stream-chat-expo`. Both packages re-export one core SDK, and each registers the native handlers of its toolchain, the functions and components that pick images, play audio or copy text with the packages you install. An app that shows AI responses also imports from the `ai-components` entry point of its package.

This page lists the entry points, what they export and which packages they need, and every native handler. [Installation](https://getstream.io/chat/docs/sdk/react-native/v10/getting-started/installation/) has the short version.

| Entry point                              | Toolchain        | What it's for                                                           | Native handlers it registers            |
| ---------------------------------------- | ---------------- | ----------------------------------------------------------------------- | --------------------------------------- |
| `stream-chat-react-native`               | React Native CLI | Components, contexts and hooks                                          | Every handler, from the RN CLI packages |
| `stream-chat-expo`                       | Expo             | Components, contexts and hooks                                          | Every handler, from the Expo packages   |
| `stream-chat-react-native/ai-components` | React Native CLI | AI components, such as streaming messages, Markdown and the AI composer | `NativeShimmerView` and `PerfText`      |
| `stream-chat-expo/ai-components`         | Expo             | AI components, such as streaming messages, Markdown and the AI composer | `NativeShimmerView` and `PerfText`      |

Install one of the two packages, never both. Metro doesn't drop unused code, so the AI components are a separate entry point, and the main entry point never imports from it. An app that never imports `ai-components` doesn't bundle them, or the packages they use.

## `stream-chat-react-native` and `stream-chat-expo`

These are the core UI. Both packages export the same components, contexts and hooks, from the core package `stream-chat-react-native-core`, which they depend on. Import from your toolchain's package, not from `stream-chat-react-native-core`. Importing the core alone registers no native handlers. Each package also exports `defaultNativeHandlers`, the handlers it registers. See [Overriding a handler](#overriding-a-handler).

The packages don't re-export `stream-chat`. Import the client and the state classes, such as `StreamChat` and `ChannelPaginator`, from `stream-chat` itself.

The main exports by area:

| Area                  | Main exports                                                                                                                   | Explained in                                                                                                                      |
| --------------------- | ------------------------------------------------------------------------------------------------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------- |
| Setup                 | `Chat`, `OverlayProvider`, `useCreateChatClient`, `useChatContext`, `Streami18n`, `useTranslationContext`                      | [Chat](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/chat/chat/)                                                            |
| Reading state         | `useStateStore`, `useChannel`, `useMessagePaginator`, `useChannelContext`, `useMessageContext`                                 | [Reading state in components](https://getstream.io/chat/docs/sdk/react-native/v10/ui/reading-state-in-components/)                                    |
| Channel list          | `ChannelList`, `ChannelListView`, `ChannelPreview`, `ChannelPreviewView`, `useChannelsContext`                                 | [Channel list UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-list-ui/)                                                 |
| Channel               | `Channel`, `KeyboardCompatibleView`, `useOwnCapabilitiesContext`                                                               | [Channel UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-ui/)                                                           |
| Message list          | `MessageList`, `MessageFlashList`, `Message`, `MessageItemView`, `Attachment`, `Gallery`, `ReactionListTop`, `TypingIndicator` | [Message list UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/)                                                 |
| Message composer      | `MessageComposer`, `AttachmentPicker`, `AutoCompleteSuggestionList`, `useMessageComposer`, `useMessageInputContext`            | [Message composer UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-composer-ui/)                                         |
| Threads               | `Thread`, `ThreadList`, `useThreadContext`, `useThreadsContext`                                                                | [Thread UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/thread-ui/)                                                             |
| Channel details       | `ChannelDetails`, `useChannelDetailsContext`, `useChannelActions`, `useUserActions`                                            | [Channel details and members](https://getstream.io/chat/docs/sdk/react-native/v10/features/channels/channel-details-and-members/)                     |
| Overriding components | `WithComponents`, `useComponentsContext` and the icon components, such as `Mute` and `SendRight`                               | [Overriding components](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overriding-components/)                                    |
| Actions               | `messageActions`, `useMessageActions`, `useChannelActionItems`                                                                 | [Actions](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/actions/)                                                                |
| Notifications         | `NotificationList`, `useNotifications`, `useClientNotifications`, `useInAppNotificationsState`                                 | [Displaying notifications](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/displaying-notifications/)                              |
| Overlays              | `BottomSheetModal`, `ImageGallery`, `useOverlayContext`, `PortalWhileClosingView`                                              | [Overlays and bottom sheets](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overlays-and-bottom-sheets/)                          |
| Theming               | `useTheme`, `ThemeProvider`, `mergeThemes`, `defaultTheme`                                                                     | [Theming](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/theming/)                                                                |
| Connection            | `useWSConnectionState`, `useNetworkConnectionState`                                                                            | [Connection status](https://getstream.io/chat/docs/sdk/react-native/v10/features/app-experience/connection-status/)                                   |
| Voice and audio       | `AudioRecorder`, `AudioAttachment`, `useAudioPlayer`                                                                           | [Voice recordings and audio playback](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/voice-recordings-and-audio-playback/) |
| Polls                 | `Poll`, `CreatePoll`, `usePollContext`                                                                                         | [Polls](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/)                                                             |
| AI state              | `AITypingIndicatorView`, `useAIState`, `StreamingMessageView`                                                                  | [SDK integration](https://getstream.io/chat/docs/sdk/react-native/v10/features/ai/sdk-integration/)                                                   |
| Accessibility         | `useAccessibilityContext`, `useAccessibilityAnnouncer`                                                                         | [Accessibility](https://getstream.io/chat/docs/sdk/react-native/v10/features/app-experience/accessibility/)                                           |
| Offline support       | `OfflineDB`, `SqliteClient`, `SqliteClientError`, `OfflineStoreApis`                                                           | [Offline support](https://getstream.io/chat/docs/sdk/react-native/v10/state/offline-support/offline-support/)                                         |
| Native handlers       | `registerNativeHandlers`, `defaultNativeHandlers`                                                                              | [Native handlers](#native-handlers)                                                                                               |

Reference, Hooks lists the hooks by state area, starting with [State and entity hooks](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/state-and-entity-hooks/). Every component's props are in the Component reference, starting with [Chat](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/chat/chat/).

## `stream-chat-react-native/ai-components` and `stream-chat-expo/ai-components`

The entry point exports the components for AI chat:

- `StreamingMessageView` renders Markdown as it streams in, with a typewriter effect, syntax highlighting, tables and charts.
- `ComposerView` is a composer with attachment previews, a bottom sheet of options, speech to text, and a send button that turns into a stop button while a response is generated. `SpeechToTextButton` is its dictation button.
- `AITypingIndicatorView` shows a state of the model, such as "Thinking", as shimmering text.
- `Markdown`, `SyntaxHighlighter` and `VictoryChart` are the renderers `StreamingMessageView` uses.
- `useStreamingMessage` drives the typewriter effect, `useDictation` the speech to text, and `isDictationAvailable()` tells whether dictation is part of the build.
- `StreamTheme` provides the theme of these components, which `useTheme` from this entry point reads. Wrap the AI components in it.

The entry point doesn't import the main entry point, so it doesn't register the main native handlers. It registers only the two native views its components use, `NativeShimmerView` and, on Android, `PerfText`, which renders highlighted code as one native text view. Importing both entry points registers them twice, which is harmless.

Several names exist in both entry points, as different exports. For example, `AITypingIndicatorView`, `StreamingMessageView` and `useStreamingMessage` from the main entry point belong to the chat UI. The theme exports of this entry point, `Theme`, `useTheme`, `defaultTheme`, `mergeThemes` and `DeepPartial`, belong to `StreamTheme`, not to the chat theme.

What the entry point needs:

- **Charts.** It imports `@shopify/react-native-skia` and `victory-native`, so an app that imports it installs both.
- **Babel.** Its `zod` dependency uses `export * as` syntax, which the React Native Babel preset doesn't transform. Add `@babel/plugin-transform-export-namespace-from` to `babel.config.js`, before `react-native-worklets/plugin`.
- **Dictation.** On iOS, the dictation module is compiled into the app only when you opt in, because App Store Connect asks every app whose binary references the Speech framework for a speech recognition usage description. With React Native CLI, set `$StreamChatEnableDictation = true` in the `Podfile`, before `use_native_modules!`, and add `NSMicrophoneUsageDescription` and `NSSpeechRecognitionUsageDescription` to `Info.plist`. On Android, add the `RECORD_AUDIO` permission to your app's `AndroidManifest.xml`. With Expo, add the `stream-chat-expo` config plugin to `app.json`, which does both. On iOS without the opt-in, `SpeechToTextButton` renders nothing and `isDictationAvailable()` returns `false`.
- **Media and clipboard.** The composer's media picker uses `react-native-image-picker` or `expo-image-picker`, and the copy button of code blocks uses `@react-native-clipboard/clipboard` or `expo-clipboard`, whichever is installed. These don't go through the native handlers.

See the [AI integrations overview](https://getstream.io/chat/docs/sdk/react-native/v10/features/ai/ai-integrations-overview/) and [SDK integration](https://getstream.io/chat/docs/sdk/react-native/v10/features/ai/sdk-integration/).

## Native handlers

The core SDK doesn't import any native package itself. It calls native handlers, a function or a component for each platform capability, such as `pickImage`, `setClipboardString` or `Video`. `stream-chat-react-native` and `stream-chat-expo` each register an implementation of every handler when they're first imported, built on the packages of their toolchain.

Each implementation checks at import time whether its package is installed. When it isn't, the package registers `null` for most handlers, and the SDK leaves out the feature. For example, without `takePhoto` the composer has no camera button, without `shareImage` the image gallery has no share button, and without `setClipboardString` the message menu has no copy action. `triggerHaptic` is the exception. Without its package, it's a function that does nothing.

### Handlers

| Handler                                | What it does                                                                                                                                                                                          | `stream-chat-react-native`                                                                                        | `stream-chat-expo`                                      |
| -------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------- |
| `Audio`                                | Records voice messages, and plays a recording back before it's sent                                                                                                                                   | `react-native-nitro-sound`, or the deprecated `react-native-audio-recorder-player`, with `react-native-blob-util` | `expo-audio`, or the deprecated `expo-av`               |
| `overrideAudioRecordingConfiguration`  | Receives the recording configuration of `Audio` and returns the one to use. It isn't kept as a handler                                                                                                | Returns the configuration unchanged                                                                               | Returns the configuration unchanged                     |
| `compressImage`                        | Compresses an image before upload, when `compressImageQuality` is set on `Channel` to a value other than 1                                                                                            | Built in. It always writes JPEG, over a white background                                                          | `expo-image-manipulator`                                |
| `deleteFile`                           | Deletes the copy of an attachment that was downloaded to share it                                                                                                                                     | `react-native-blob-util`                                                                                          | `expo-file-system`                                      |
| `FlatList`                             | The `FlatList` component `MessageList` renders. A `FlatList` prop on `Channel` takes precedence                                                                                                       | React Native's `FlatList`                                                                                         | React Native's `FlatList`                               |
| `getLocalAssetUri`                     | Resolves a photo library asset to a local file. The SDK checks that it's registered before it shows the media grid. The native uploader uses the package's own implementation, not the registered one | `@react-native-camera-roll/camera-roll`                                                                           | `expo-media-library`                                    |
| `getPhotos`                            | Pages through the photo library, for the media grid of the attachment picker                                                                                                                          | `@react-native-camera-roll/camera-roll`                                                                           | `expo-media-library`                                    |
| `iOS14RefreshGallerySelection`         | Opens the iOS picker that changes which photos a limited library grants                                                                                                                               | `@react-native-camera-roll/camera-roll`                                                                           | `expo-media-library`                                    |
| `oniOS14GalleryLibrarySelectionChange` | Subscribes to changes of that selection                                                                                                                                                               | `@react-native-camera-roll/camera-roll`                                                                           | `expo-media-library`                                    |
| `multipartUpload`                      | Uploads files with the SDK's native uploader, when `useNativeMultipartUpload` is set on `Chat`                                                                                                        | Built in                                                                                                          | Built in                                                |
| `NativeShimmerView`                    | The shimmer of loading placeholders                                                                                                                                                                   | Built in                                                                                                          | Built in                                                |
| `PerfText`                             | The native text view of highlighted code in the AI components, on Android                                                                                                                             | Built in, registered by the `ai-components` entry point                                                           | Built in, registered by the `ai-components` entry point |
| `pickDocument`                         | Opens the system file picker                                                                                                                                                                          | `@react-native-documents/picker`                                                                                  | `expo-document-picker`                                  |
| `pickImage`                            | Opens the system image picker, for attachments and the channel image                                                                                                                                  | `react-native-image-picker`                                                                                       | `expo-image-picker`                                     |
| `saveFile`                             | Downloads an attachment to the cache directory, to share it                                                                                                                                           | `react-native-blob-util`                                                                                          | `expo-file-system`                                      |
| `SDK`                                  | The name of the package, which the SDK reports to Stream as the SDK identifier                                                                                                                        | `"stream-chat-react-native"`                                                                                      | `"stream-chat-expo"`                                    |
| `setClipboardString`                   | Copies a message's text                                                                                                                                                                               | `@react-native-clipboard/clipboard`                                                                               | `expo-clipboard`                                        |
| `shareImage`                           | Opens the system share sheet for an attachment in the image gallery                                                                                                                                   | `react-native-share`                                                                                              | `expo-sharing`                                          |
| `Sound`                                | Plays audio attachments and voice recordings                                                                                                                                                          | `react-native-nitro-sound`, or the deprecated `react-native-audio-recorder-player`                                | `expo-audio`, or the deprecated `expo-av`               |
| `takePhoto`                            | Opens the camera, for attachments and the channel image                                                                                                                                               | `react-native-image-picker`                                                                                       | `expo-image-picker`                                     |
| `triggerHaptic`                        | Plays haptic feedback, on long presses, in the audio recorder and in the image gallery                                                                                                                | `react-native-haptic-feedback`                                                                                    | `expo-haptics`                                          |
| `Video`                                | Plays videos in the image gallery                                                                                                                                                                     | `react-native-video`                                                                                              | `expo-video`                                            |

Where a package is listed with a fallback, the handler uses the first package that is installed. A few handlers need more than one package to turn a feature on. The share button of the image gallery needs `shareImage` and a file system handler, `saveFile` or `deleteFile`. The media grid of the attachment picker needs `getPhotos`, `getLocalAssetUri` and both iOS 14 handlers.

### Overriding a handler

`registerNativeHandlers()` takes an object with the handlers to replace, and keeps the others. Call it once, at the top level of a module, after the import of `stream-chat-react-native` or `stream-chat-expo`, so it runs after the package has registered its defaults. Calls inside a component run again on every render.

To change what a default handler does, wrap it. `defaultNativeHandlers` holds the handlers the package registered, with `null` for most of those whose package isn't installed. This override makes the camera button take photos only, never videos:

**RN CLI**

```ts title="nativeHandlers.ts"
import {
  defaultNativeHandlers,
  registerNativeHandlers,
} from "stream-chat-react-native";

const defaultTakePhoto = defaultNativeHandlers.takePhoto;

if (defaultTakePhoto) {
  registerNativeHandlers({
    takePhoto: (options) =>
      defaultTakePhoto({ ...options, mediaType: "image" }),
  });
}
```

**Expo**

```ts title="nativeHandlers.ts"
import {
  defaultNativeHandlers,
  registerNativeHandlers,
} from "stream-chat-expo";

const defaultTakePhoto = defaultNativeHandlers.takePhoto;

if (defaultTakePhoto) {
  registerNativeHandlers({
    takePhoto: (options) =>
      defaultTakePhoto({ ...options, mediaType: "image" }),
  });
}
```

Import the file once, for example from the file that renders `OverlayProvider`. The SDK reads a handler each time it uses it, so an override applies from then on. Register overrides before the first render, so every part of the UI uses them.

To replace a handler, register your own function with the same signature. For example, to turn off haptic feedback:

```ts title="nativeHandlers.ts"
import { registerNativeHandlers } from "stream-chat-react-native";

registerNativeHandlers({
  triggerHaptic: () => {},
});
```

With React Native CLI, wrapping `compressImage` is also how you set the color painted behind transparent images. The SDK passes only the quality, the size and the URI, and the default handler paints white unless it gets `backgroundColor`, a color string or an RGBA integer:

```ts title="nativeHandlers.ts"
import {
  defaultNativeHandlers,
  registerNativeHandlers,
} from "stream-chat-react-native";

const defaultCompressImage = defaultNativeHandlers.compressImage;

if (defaultCompressImage) {
  registerNativeHandlers({
    compressImage: (params) =>
      defaultCompressImage({ ...params, backgroundColor: "#000000" }),
  });
}
```

Pass `backgroundColor: null` to leave the background to the platform. `stream-chat-expo` has no such option.

`overrideAudioRecordingConfiguration` changes the recording settings of the registered `Audio`. It receives the current configuration and returns the new one, which the SDK sets on `Audio` when you register it. Without a registered `Audio`, it has no effect. The configuration types are `RNCLIAudioRecordingConfiguration` and `ExpoAudioRecordingConfiguration`.

### Handler types

The parameter of `registerNativeHandlers()` types every handler. The SDK doesn't export a type for each one, so derive it:

```ts
import type { registerNativeHandlers } from "stream-chat-react-native";

type NativeHandlers = Parameters<typeof registerNativeHandlers>[0];
type TakePhoto = NonNullable<NativeHandlers["takePhoto"]>;
```

`PickImageOptions`, `PlaybackStatus`, `RecordingStatus` and `SoundReturnType`, the types of the handlers' data, are exported too.

## Optional packages

The core SDK and each package declare their optional packages as optional peer dependencies. Install one only if you use the feature that needs it. The required peers are on [Installation](https://getstream.io/chat/docs/sdk/react-native/v10/getting-started/installation/).

Both toolchains:

| Package                      | Version    | Needed by                                                                                     |
| ---------------------------- | ---------- | --------------------------------------------------------------------------------------------- |
| `@op-engineering/op-sqlite`  | `>=14.0.0` | Offline support, with `enableOfflineSupport` on `Chat`                                        |
| `@shopify/flash-list`        | `>=2.1.0`  | `MessageFlashList`                                                                            |
| `@shopify/react-native-skia` | `>=2.0.0`  | The `ai-components` entry point, for charts                                                   |
| `victory-native`             | `>=41.0.0` | The `ai-components` entry point, for charts                                                   |
| `emoji-mart`                 | `>=5.4.0`  | Nothing in the SDK imports it. Its `SearchIndex` can feed `createTextComposerEmojiMiddleware` |
| `@emoji-mart/data`           | `>=1.1.0`  | Nothing in the SDK imports it. The emoji data for `emoji-mart`                                |

`stream-chat-react-native`:

| Package                                 | Version    | Needed by                                                                   |
| --------------------------------------- | ---------- | --------------------------------------------------------------------------- |
| `react-native-video`                    | `>=6.18.0` | `Video`                                                                     |
| `react-native-nitro-sound`              | `>=0.2.9`  | `Audio` and `Sound`. It needs `react-native-nitro-modules`                  |
| `react-native-audio-recorder-player`    | `>=3.6.13` | `Audio` and `Sound`, deprecated. Install `react-native-nitro-sound` instead |
| `react-native-blob-util`                | `>=0.22.0` | `Audio`, `saveFile` and `deleteFile`                                        |
| `react-native-share`                    | `>=11.0.0` | `shareImage`                                                                |
| `react-native-haptic-feedback`          | `>=2.3.0`  | `triggerHaptic`                                                             |
| `@react-native-clipboard/clipboard`     | `>=1.16.0` | `setClipboardString`                                                        |
| `@react-native-documents/picker`        | `>=10.1.1` | `pickDocument`                                                              |
| `react-native-image-picker`             | `>=7.1.2`  | `pickImage` and `takePhoto`                                                 |
| `@react-native-camera-roll/camera-roll` | `>=7.9.0`  | `getPhotos`, `getLocalAssetUri` and the iOS 14 handlers                     |

`stream-chat-expo` needs Expo SDK 53 or later. Its packages take any version:

| Package                  | Needed by                                                                   |
| ------------------------ | --------------------------------------------------------------------------- |
| `expo-image-manipulator` | `compressImage`. `stream-chat-expo` imports it when it loads, so install it |
| `expo-video`             | `Video`                                                                     |
| `expo-audio`             | `Audio` and `Sound`                                                         |
| `expo-av`                | `Audio` and `Sound`, deprecated. Install `expo-audio` instead               |
| `expo-file-system`       | `saveFile` and `deleteFile`                                                 |
| `expo-sharing`           | `shareImage`                                                                |
| `expo-haptics`           | `triggerHaptic`                                                             |
| `expo-clipboard`         | `setClipboardString`                                                        |
| `expo-document-picker`   | `pickDocument`                                                              |
| `expo-image-picker`      | `pickImage` and `takePhoto`                                                 |
| `expo-media-library`     | `getPhotos`, `getLocalAssetUri` and the iOS 14 handlers                     |

Most of these are native modules, so rebuild the app after adding one.

## Best practices

- Import from `stream-chat-react-native` or `stream-chat-expo`, never from `stream-chat-react-native-core`, so the native handlers are registered.
- Import `ai-components` only if the app renders AI components. One import anywhere in the app bundles them, with the packages they need.
- Register handler overrides once, at the top level of a module, before the first render.
- Wrap the default handler from `defaultNativeHandlers` rather than rewriting it, and keep its signature.
- Install only the optional packages of the features you use, and add the permissions each one needs.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/reference/entry-points-and-native-handlers/](https://getstream.io/chat/docs/sdk/react-native/v10/reference/entry-points-and-native-handlers/).