---
id: channel_list
title: ChannelList
---

import CodeBlock from '@theme/CodeBlock';

import GHComponentLink from '../../_docusaurus-components/GHComponentLink';

The `ChannelList` component queries an array of `channel` objects from the Stream Chat API and displays as a customizable list
in the UI. It accepts props for [`filters`](#filters), [`sort`](#sort) and [`options`](#options), which allows you to tailor
your request to the [Query Channels](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript) API. The
response array from this API is then rendered in a list and loaded into the DOM.

```jsx
const channels = await client.queryChannels(filters, sort, options);
```

The `ChannelList` component also comes pre-built with navigation functionality. The click of a list item sets the active
`channel` object and loads the [`Channel`](./channel.mdx) component.

## Basic Usage

The `ChannelList` does not have any required props, but in order to refine channel query results we recommend providing
values for [`filters`](#filters), [`sort`](#sort) and [`options`](#options).

:::caution
By default when channels query does not have any filter it will match all the channels in your application. While this might be convenient during the development, you most likely want to have at least some basic filtering.

**At a minimum, the filter should include `{members: { $in: [userID] }}` .**
:::

```jsx
const filters = { members: { $in: [ 'jimmy', 'buffet' ] } }
const sort = { last_message_at: -1 };
const options = { limit: 10 }

<Chat client={client}>
  <ChannelList filters={filters} sort={sort} options={options} />
  <Channel>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>
```

## UI Customization

`ChannelList` UI is determined by two of its props, `List` and `Preview`. The `List` prop allows you to customize the container
in which the array of channels is rendered. The `Preview` prop dictates the design and click functionality of an individual
channel in the list. If not provided via props, these UI components default to
[`ChannelListMessenger`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelList/ChannelListMessenger.tsx)
and [`ChannelPreviewMessenger`](https://github.com/GetStream/stream-chat-react/blob/master/src/components/ChannelPreview/ChannelPreviewMessenger.tsx).

To customize the container and list item UI for your `ChannelList`, provide custom component overrides. Your custom components
will receive the same props as the defaults.

```jsx
const CustomListContainer = (props) => {
  // render custom list container here
};

const CustomListItem = (props) => {
  // render custom list item here
};

<Chat client={client}>
  <ChannelList List={CustomListContainer} Preview={CustomListItem} />
  <Channel>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>;
```

In cases where the customizations provided by `Preview` are not enough, e.g. grouping channels under sections based on some
dynamic channel data, the `renderChannels` may be a good fit as all loaded channels are passed as an argument to the function.

```jsx
const renderChannels = (loadedChannels, ChannelPreview) => {
  const groups = groupBy(loadedChannels, 'some_custom_channel_data');
  return renderGroups(groups); // inside renderGroups you have have headings, etc...
}

<Chat client={client}>
  <ChannelList {/* other props */} renderChannels={renderChannels} />
  <Channel>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>;
```

## Event Listeners

In order to handle the requisite, dynamic nature of the `ChannelList`, a variety of
[event listeners](https://getstream.io/chat/docs/javascript/event_listening/?language=javascript) are added on component mount.
Many of these event listeners accept custom handler functions, allowing you to override the library's default event response behavior.

Each custom handler accepts the same function arguments. Through a combination of pulling updated data off the event object and
re-setting the list state, you can customize behavior and UI.

- `setChannels` - state setter for the `channels` value which populates the list in the DOM
- `event` - event object returned from each corresponding event listener

| [Event Type](https://getstream.io/chat/docs/javascript/event_object/?language=javascript) | Default Behavior                                 | Custom Handler                                |
| ----------------------------------------------------------------------------------------- | ------------------------------------------------ | --------------------------------------------- |
| `channel.deleted`                                                                         | Removes channel from list                        | [onChannelDeleted](#onchanneldeleted)         |
| `channel.hidden`                                                                          | Removes channel from list                        | [onChannelHidden](#onchannelhidden)           |
| `channel.truncated`                                                                       | Updates the channel                              | [onChannelTruncated](#onchanneltruncated)     |
| `channel.updated`                                                                         | Updates the channel                              | [onChannelUpdated](#onchannelupdated)         |
| `channel.visible`                                                                         | Adds channel to list                             | [onChannelVisible](#onchannelvisible)         |
| `connection.recovered`                                                                    | Forces a component render                        | N/A                                           |
| `message.new`                                                                             | Moves channel to top of list                     | [onMessageNewHandler](#onmessagenewhandler)   |
| `notification.added_to_channel`                                                           | Moves channel to top of list and starts watching | [onAddedToChannel](#onaddedtochannel)         |
| `notification.message_new`                                                                | Moves channel to top of list and starts watching | [onMessageNew](#onmessagenew)                 |
| `notification.removed_from_channel`                                                       | Removes channel from list                        | [onRemovedFromChannel](#onremovedfromchannel) |
| `user.presence.changed`                                                                   | Updates the channel                              | N/A                                           |

## Customizing Event Handlers

The event type the `ChannelList` reacts to and its corresponding behavior can be overridden using the appropriate prop. Let's look at an example of customizing the ChannelList component to only display [frozen channels](https://getstream.io/chat/docs/javascript/freezing_channels/).

```tsx
const filters = {
  members: { $in: ['dan'] },
  frozen: true
}

<ChannelList filters={filters} />
```

The `notification.message_new` event occurs when a message is received on a channel that is not loaded but the current user is a member of.
The default behavior when this event occurs is to query the channel the message is received on, then add the channel to the top of the list, irrespective of `filters`.
Thus, if a new message appears in an unfrozen channel of which the current user is a member, it will be added to the list. This may not be the desired behavior since the list is only supposed to show frozen channels.

In this case, you can replace the default functionality by providing a custom `onMessageNew` function as a prop to the `ChannelList` component.
`onMessageNew` receives two parameters when called, `setChannels`, a setter function for the internal `channels` state, and `event`, the `Event` object received for the `notification.message_new` event.
These parameters can be used to create a function that achieves the desired custom behavior.

```tsx
const filters = {
  members: { $in: ['dan'] },
  frozen: true,
};

const customOnMessageNew = async (setChannels, event) => {
  const eventChannel = event.channel;

  // If the channel isn't frozen, then don't add it to the list.
  if (!eventChannel?.id || !eventChannel.frozen) return;

  try {
    const newChannel = client.channel(eventChannel.type, eventChannel.id);
    await newChannel.watch();
    setChannels((channels) => [newChannel, ...channels]);
  } catch (error) {
    console.log(error);
  }
};

<ChannelList filters={filters} onMessageNew={customOnMessageNew} />;
```

Similarly, events other than `notification.message_new` can be handled as per application requirements.

## Props

### additionalChannelSearchProps

Additional props to be passed to the underlying [`ChannelSearch`](../utility-components/channel-search.mdx) component.

| Type   |
| ------ |
| object |

### allowNewMessagesFromUnfilteredChannels

When the client receives `message.new`, `notification.message_new`, and `notification.added_to_channel` events, we automatically push
that channel to the top of the list. If the channel doesn't currently exist in the list, we grab the channel from `client.activeChannels`
and push it to the top of the list. You can disable this behavior by setting this prop to false, which will prevent channels not in the
list from incrementing the list.

| Type    | Default |
| ------- | ------- |
| boolean | true    |

### Avatar

Custom UI component to display the user's avatar.

| Type      | Default                                                    |
| --------- | ---------------------------------------------------------- |
| component | <GHComponentLink text='Avatar' path='/Avatar/Avatar.tsx'/> |

### channelRenderFilterFn

Optional function to filter channels prior to loading in the DOM. Do not use any complex or async logic that would delay the
loading of the `ChannelList`. We recommend using a pure function with array methods like filter/sort/reduce.

| Type                               |
| ---------------------------------- |
| (channels: Channel[]) => Channel[] |

### ChannelSearch

Custom UI component to display search results.

| Type      | Default                                                                         |
| --------- | ------------------------------------------------------------------------------- |
| component | <GHComponentLink text='ChannelSearch' path='/ChannelSearch/ChannelSearch.tsx'/> |

### customActiveChannel

Set a channel (with this ID) to active and force it to move to the top of the list.

| Type   |
| ------ |
| string |

### customQueryChannels

Custom function that handles the channel pagination.

Takes parameters:

| Parameter         | Description                                                                                                                                                           |
| ----------------- | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `currentChannels` | The state of loaded `Channel` objects queried thus far. Has to be set with `setChannels` (see below).                                                                 |
| `queryType`       | A string indicating, whether the channels state has to be reset to the first page ('reload') or newly queried channels should be appended to the `currentChannels`.   |
| `setChannels`     | Function that allows us to set the channels state reflected in `currentChannels`.                                                                                     |
| `setHasNextPage`  | Flag indicating whether there are more items to be loaded from the API. Should be infered from the comparison of the query result length and the query options limit. |

The function has to:

1. build / provide own query filters, sort and options parameters
2. query and append channels to the current channels state
3. update the `hasNext` pagination flag after each query with `setChannels` function

An example below implements a custom query function that uses different filters sequentially once a preceding filter is exhausted:

```ts
import uniqBy from 'lodash.uniqby';
import throttle from 'lodash.throttle';
import { useCallback, useRef } from 'react';
import { ChannelFilters, ChannelOptions, ChannelSort, StreamChat } from 'stream-chat';
import { CustomQueryChannelParams, useChatContext } from 'stream-chat-react';

const DEFAULT_PAGE_SIZE = 30 as const;

export const useCustomQueryChannels = () => {
  const { client } = useChatContext();
  const filters1: ChannelFilters = {
    member_count: { $gt: 10 },
    members: { $in: [client.user?.id || ''] },
    type: 'messaging',
  };
  const filters2: ChannelFilters = { members: { $in: [client.user?.id || ''] }, type: 'messaging' };
  const options: ChannelOptions = { limit: 10, presence: true, state: true };
  const sort: ChannelSort = { last_message_at: -1, updated_at: -1 };

  const filtersArray = [filters1, filters2];
  const appliedFilterIndex = useRef(0);

  const customQueryChannels = useCallback(
    throttle(
      async ({
        currentChannels,
        queryType,
        setChannels,
        setHasNextPage,
      }: CustomQueryChannelParams) => {
        const offset = queryType === 'reload' ? 0 : currentChannels.length;

        const newOptions = {
          limit: options.limit ?? DEFAULT_PAGE_SIZE,
          offset,
          ...options,
        };

        const filters = filtersArray[appliedFilterIndex.current];
        const channelQueryResponse = await client.queryChannels(filters, sort || {}, newOptions);

        const newChannels =
          queryType === 'reload'
            ? channelQueryResponse
            : uniqBy([...currentChannels, ...channelQueryResponse], 'cid');

        setChannels(newChannels);

        const lastPageForCurrentFilter = channelQueryResponse.length < newOptions.limit;
        const isLastPageForAllFilters =
          lastPageForCurrentFilter && appliedFilterIndex.current === filtersArray.length - 1;

        setHasNextPage(!isLastPageForAllFilters);
        if (lastPageForCurrentFilter) {
          appliedFilterIndex.current += 1;
        }
      },
      500,
      { leading: true, trailing: false },
    ),
    [client, filtersArray],
  );

  return customQueryChannels;
};
```

It is recommended to control for duplicate requests by throttling the custom function calls.

| Type                                                                                              |
| ------------------------------------------------------------------------------------------------- |
| <GHComponentLink text='CustomQueryChannelsFn' path='/ChannelList/hooks/usePaginatedChannels.ts'/> |

### EmptyStateIndicator

Custom UI component for rendering an empty list.

| Type      | Default                                                                                           |
| --------- | ------------------------------------------------------------------------------------------------- |
| component | <GHComponentLink text='EmptyStateIndicator' path='/EmptyStateIndicator/EmptyStateIndicator.tsx'/> |

### filters

An object containing channel query filters, check our [query parameters docs](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript#query-parameters)
for more information.

| Type   |
| ------ |
| object |

### getLatestMessagePreview

Custom function that generates the message preview in ChannelPreview component.

| Type                                                                                                                                  |
| ------------------------------------------------------------------------------------------------------------------------------------- |
| `(channel: Channel, t: TranslationContextValue['t'], userLanguage: TranslationContextValue['userLanguage']) => string \| JSX.Element` |

### List

Custom UI component to display the container for the queried channels.

| Type      | Default                                                                                     |
| --------- | ------------------------------------------------------------------------------------------- |
| component | <GHComponentLink text='ChannelListMessenger' path='/ChannelList/ChannelListMessenger.tsx'/> |

### LoadingErrorIndicator

Custom UI component to display the loading error indicator.

| Type      | Default                                                          |
| --------- | ---------------------------------------------------------------- |
| component | <GHComponentLink text='ChatDown' path='/ChatDown/ChatDown.tsx'/> |

### LoadingIndicator

Custom UI component to display the loading state.

| Type      | Default                                                                       |
| --------- | ----------------------------------------------------------------------------- |
| component | <GHComponentLink text='LoadingChannels' path='/Loading/LoadingChannels.tsx'/> |

### lockChannelOrder

When true, channels won't dynamically sort by most recent message.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### onAddedToChannel

Function to override the default behavior when a user is added to a channel.

| Type     |
| -------- |
| function |

### onChannelDeleted

Function to override the default behavior when a channel is deleted.

| Type     |
| -------- |
| function |

### onChannelHidden

Function to override the default behavior when a channel is hidden.

| Type     |
| -------- |
| function |

### onChannelTruncated

Function to override the default behavior when a channel is truncated.

| Type     |
| -------- |
| function |

### onChannelUpdated

Function to override the default behavior when a channel is updated.

| Type     |
| -------- |
| function |

### onChannelVisible

Function to override the default channel visible behavior.

| Type     |
| -------- |
| function |

### onMessageNew

Function to override the default behavior when a message is received on a channel not being watched.

| Type     |
| -------- |
| function |

### onMessageNewHandler

Function to override the default behavior when a message is received on a channel being watched. Handles `message.new` event.

| Type                                                                                                                                |
| ----------------------------------------------------------------------------------------------------------------------------------- |
| `(setChannels: React.Dispatch<React.SetStateAction<Array<Channel<StreamChatGenerics>>>>, event: Event<StreamChatGenerics>) => void` |

### onRemovedFromChannel

Function to override the default behavior when a user gets removed from a channel.

| Type     |
| -------- |
| function |

### options

An object containing channel query options, check our [query parameters docs](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript#query-parameters)
for more information.

| Type   |
| ------ |
| object |

### Paginator

Custom UI component to handle channel pagination logic.

| Type      | Default                                                                            |
| --------- | ---------------------------------------------------------------------------------- |
| component | <GHComponentLink text='LoadMorePaginator' path='/LoadMore/LoadMorePaginator.tsx'/> |

### Preview

Custom UI component to display the channel preview in the list.

| Type      | Default                                                                                              |
| --------- | ---------------------------------------------------------------------------------------------------- |
| component | <GHComponentLink text='ChannelPreviewMessenger' path='/ChannelPreview/ChannelPreviewMessenger.tsx'/> |

### recoveryThrottleIntervalMs

Custom interval during which the recovery channel list queries will be prevented. This is to avoid firing unnecessary queries during internet connection fluctuation. Recovery channel query is triggered upon internet connection recovery and leads to complete channel list reload with pagination offset 0. The minimum throttle interval is 2000ms. The default throttle interval is 5000ms.

The channel list recovery mechanism described here (applying `recoveryThrottleIntervalMs`) **is activated only if the `StreamChat` client's channel list recovery mechanism is disabled**. The `StreamChat` recovery mechanism can be disabled when initiating the client instance through the `options` parameter:

```typescript jsx
import { StreamChat } from 'stream-chat';
import { ChannelList, Chat } from 'stream-chat-react';

// ... get apiKey, filters, sort, options

const client = new StreamChat(apiKey, {recoverStateOnReconnect: false});
const App = () => (
    <Chat client={client} >
     {/** ... */}
        <ChannelList
        filters={filters}
        sort={sort}
        options={options}
        recoveryThrottleIntervalMs={3000}
        {/** other props... */}
      />
     {/** ... */}
    </Chat>
);

```

| Type   | Default |
| ------ | ------- |
| number | 5000    |

### renderChannels

Function to override the default behavior when rendering channels, so this function is called instead of rendering the Preview directly.

| Type     |
| -------- |
| function |

### sendChannelsToList

If true, sends the list's currently loaded channels to the `List` component as the `loadedChannels` prop.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### setActiveChannelOnMount

If true, sets the most recent channel received from the query as active on component mount. If set to `false` no channel is set as active on mount.

| Type    | Default |
| ------- | ------- |
| boolean | true    |

### showChannelSearch

If true, renders the [`ChannelSearch`](./#channelsearch) component above the [`List`](./#list) component.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### sort

An object containing channel query sort parameters. Check our [query parameters docs](https://getstream.io/chat/docs/javascript/query_channels/?language=javascript#query-parameters)
for more information.

| Type   |
| ------ |
| object |

### watchers

An object containing query parameters for fetching channel watchers.

| Type                                  |
| ------------------------------------- |
| `{ limit?: number; offset?: number }` |
