# Overview

Building chat from scratch in React Native is complex: state, styling, message grouping, read states, context menus, and more. Stream Chat for React Native provides a flexible, customizable UI so you can ship quickly and tailor the experience.

Before starting, install `stream-chat-react-native` as directed in the [getting started](https://getstream.io/chat/docs/sdk/react-native/) guide.

## Best Practices

- Create a single `StreamChat` client instance and reuse it throughout the app.
- Connect users with secure server-generated tokens; use developer tokens only for local testing.
- Use `useCreateChatClient` or manage connect/disconnect explicitly to avoid duplicate connections.
- Initialize channels once and remove setup code after creation to avoid accidental duplicates.
- Wrap UI in `OverlayProvider` and `Chat` at the highest sensible level to keep contexts consistent.

## Creating a Chat Client

Stream Chat for React Native uses [`stream-chat`](https://github.com/GetStream/stream-chat-js), Stream's JavaScript client.
`stream-chat` is included as a dependency.

>
> **Note:** You don't have to explicitly install `stream-chat` in your project.
>

Sign up for a [Free subscription](https://getstream.io/chat/pricing/) to get your API key.

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

const client = StreamChat.getInstance("api_key");
```

## Connecting a User

Tokens authenticate users. Typically, you send the token from your backend when the user registers or logs in. See [Tokens & Authentication](https://getstream.io/chat/docs/javascript/tokens-and-authentication/) for details. You can use a [developer token](https://getstream.io/chat/docs/javascript/tokens-and-authentication/#developer-tokens) for local testing.

Call `connectUser` with the user object and `user_token` after creating the client.

```ts
await client.connectUser(
  {
    id: "jlahey",
    name: "Jim Lahey",
    image: "https://i.imgur.com/fR9Jz14.png",
  },
  "user_token",
);
```

Avoid repeated `connectUser` calls; reconnecting without disconnecting will warn and can throw.

To disconnect, call `disconnectUser`.

```ts
await client.disconnectUser();
```

>
> **Tip:** You can also use `useCreateChatClient` from `stream-chat-react-native`/`stream-chat-expo` to handle connect/disconnect automatically.
>

## Creating a Channel

Channels hold messages and interactions. Create one before rendering UI components.

A [channel type](https://getstream.io/chat/docs/javascript/creating-channels/#channel-data) controls settings for a channel. There are 5 defaults:

- `commerce`
- `gaming`
- `livestream`
- `messaging`
- `team`

You can also define custom channel types.

A channel must be initialized with either an `id` or a list of members. If you pass members, the backend auto-generates an `id`.

>
> **Note:** You can't add or remove members from a channel created using a members list.
>

You can add custom data as long as the total custom fields size is _less than 5KB_.

For this guide, create a channel once (by `id` or members list) and remove the setup code after.

**Channel Id**

```ts
/**
 *  Channel created using a channel id
 */
const channel = client.channel("messaging", "the_park", {
  name: "The Park",
});
```

**Members List**

```ts
/**
 *  Channel created using a members list
 */
const channel = client.channel("messaging", {
  members: ["jlahey", "rlafleur"],
  name: "The Park",
});
```

To create this channel on the server you must call `create` on the new channel instance.

```ts
await channel.create();
```

>
> **Note:** For on-the-fly channel creation, call `watch` to create and subscribe to updates.
>

## Configuring UI Components

With a `client`, a connected user, and a channel, you can set up UI components.

All major components rely on React contexts provided by top-level `Providers`.

### Overlay Provider

`OverlayProvider` is the top-level provider. It enables message actions, the full-screen image viewer, and the `AttachmentPicker` as a keyboard-style view.

You can use it with defaults or customize via props.

For details, see the [OverlayProvider docs](https://getstream.io/chat/docs/sdk/react-native/core-components/overlay-provider/), including how to use the `OverlayProvider` with [React Navigation](https://reactnavigation.org/).

```tsx
import { OverlayProvider } from "stream-chat-react-native";

export const Screen = () => (
  <OverlayProvider>{/** App components */}</OverlayProvider>
);
```

### Chat

`Chat` is the next provider below `OverlayProvider` and is required. Wrap the entire app or a specific screen. It requires `client` (the `StreamChat` instance [you created](#creating-a-chat-client)).

See the [Chat component docs](https://getstream.io/chat/docs/sdk/react-native/core-components/chat/) for theming and translations.

**App**

```tsx {7-9}
import { StreamChat } from "stream-chat";
import { Chat, OverlayProvider } from "stream-chat-react-native";

const client = StreamChat.getInstance("api_key");

export const App = () => (
  <OverlayProvider>
    <Chat client={client}>{/** App components */}</Chat>
  </OverlayProvider>
);
```

**Screen**

```tsx
import { StreamChat } from "stream-chat";
import { Chat } from "stream-chat-react-native";

const client = StreamChat.getInstance("api_key");

export const Screen = () => (
  <Chat client={client}>{/** App components */}</Chat>
);
```

```tsx {6}
import { OverlayProvider } from "stream-chat-react-native";
import { Screen } from "./Screen";

export const App = () => (
  <OverlayProvider>
    <Screen />
  </OverlayProvider>
);
```

## Channel List

`ChannelList` renders channels the user can access. Provide `onSelect` to handle navigation or store the selected `Channel`.

See the [ChannelList component docs](https://getstream.io/chat/docs/sdk/react-native/core-components/channel-list/) for filtering and sorting.

Render `ChannelList` inside the providers [above](#configuring-ui-components). The example assumes the client and user are already set up.

![ChannelList](https://getstream.io/docs-assets/images/fca7b8a649c0.png)

```tsx {9}
import { StreamChat } from "stream-chat";
import { ChannelList, Chat, OverlayProvider } from "stream-chat-react-native";

const client = StreamChat.getInstance("api_key");

export const App = () => (
  <OverlayProvider>
    <Chat client={client}>
      <ChannelList />
    </Chat>
  </OverlayProvider>
);
```

These components render a [`FlatList`](https://reactnative.dev/docs/flatlist) of channels for the connected user.

## Channel

`Channel` wraps the chat UI and provides contexts. It is the main entry point for customizing the chat experience.

For customization and keyboard offsets, see the [Channel component docs.](https://getstream.io/chat/docs/sdk/react-native/core-components/channel/)

`Channel` requires the `channel` prop, a `StreamChat` `Channel` instance. Create it [as above](#creating-a-channel), read it from `client.activeChannels`, or store it from `ChannelList`.

```tsx {8,11-15}
import React, { useState } from "react";
import { Channel as ChannelType, StreamChat } from "stream-chat";
import { ChannelList, Chat, OverlayProvider } from "stream-chat-react-native";

const client = StreamChat.getInstance("api_key");

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel channel={channel}>{/** App components */}</Channel>
        ) : (
          <ChannelList onSelect={setChannel} />
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

### Message List

`Channel` alone renders no UI. Add `MessageList` to render messages. It has no required props and works out of the box with `Channel`.

For `FlatList` props or threads, see the [MessageList component docs.](https://getstream.io/chat/docs/sdk/react-native/ui-components/message-list/)

![MessageList](https://getstream.io/docs-assets/images/da1e67d922ff.png)

```tsx {15}
import React, { useState } from "react";
import { Channel as ChannelType, StreamChat } from "stream-chat";
import { ChannelList, Chat, OverlayProvider } from "stream-chat-react-native";

const client = StreamChat.getInstance("api_key");

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel channel={channel}>
            <MessageList />
          </Channel>
        ) : (
          <ChannelList onSelect={setChannel} />
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

### Message Composer

To send messages, render `MessageComposer` below `MessageList`. It has no required props.

Set `keyboardVerticalOffset` on `Channel` to your header height. When a native navigation header is present, pass the same value as `topInset` so the attachment picker bottom sheet reaches its full snap point.

For customization or thread usage, see the [MessageComposer component docs.](https://getstream.io/chat/docs/sdk/react-native/ui-components/message-composer/)

![MessageComposer](https://getstream.io/docs-assets/images/2b72a14e6673.png)

```tsx
import React, { useState } from "react";
import { useHeaderHeight } from "@react-navigation/elements";
import { Channel as ChannelType, StreamChat } from "stream-chat";
import { ChannelList, Chat, OverlayProvider } from "stream-chat-react-native";

const client = StreamChat.getInstance("api_key");

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();
  const headerHeight = useHeaderHeight();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel
            channel={channel}
            keyboardVerticalOffset={headerHeight}
            topInset={headerHeight}
          >
            <MessageList />
            <MessageComposer />
          </Channel>
        ) : (
          <ChannelList onSelect={setChannel} />
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

This renders a channel list and swaps in a functional message list + input when a channel is selected.

### Thread

`Thread` renders threaded replies. On mobile, threads typically live on a separate screen, so you must handle selection and navigation. Use `onThreadSelect` on `MessageList` to set a `thread` state and render `Thread`. This example has no back navigation (pseudo-navigation only).

For `onThreadDismount` and other details, see the [Thread component docs.](https://getstream.io/chat/docs/sdk/react-native/ui-components/thread/)

![Thread](https://getstream.io/docs-assets/images/b9b94ef36122.png)

```tsx
import React, { useState } from "react";
import { useHeaderHeight } from "@react-navigation/elements";
import { Channel as ChannelType, LocalMessage, StreamChat } from "stream-chat";
import { ChannelList, Chat, OverlayProvider } from "stream-chat-react-native";

const client = StreamChat.getInstance("api_key");

export const App = () => {
  const [channel, setChannel] = useState<ChannelType>();
  const [thread, setThread] = useState<LocalMessage | null>();
  const headerHeight = useHeaderHeight();

  return (
    <OverlayProvider>
      <Chat client={client}>
        {channel ? (
          <Channel
            channel={channel}
            keyboardVerticalOffset={headerHeight}
            topInset={headerHeight}
            thread={thread}
            threadList={!!thread}
          >
            {thread ? (
              <Thread />
            ) : (
              <>
                <MessageList onThreadSelect={setThread} />
                <MessageComposer />
              </>
            )}
          </Channel>
        ) : (
          <ChannelList onSelect={setChannel} />
        )}
      </Chat>
    </OverlayProvider>
  );
};
```

## Summary

- Create a `StreamChat` client, connect a user, and pass the client to `Chat` (inside `OverlayProvider`).
- Render `ChannelList`, then use the selected `Channel` to render `MessageList` + `MessageComposer`.
- Use `Thread` and `onThreadSelect` for threaded replies.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/ui-components/overview/](https://getstream.io/chat/docs/sdk/react-native/ui-components/overview/).