# Channel List UI

![](@chat-sdk/react/v13/_assets/channel-list.png)

[`ChannelList`](/chat/docs/sdk/react/v13/components/core-components/channel_list/) is the primary navigation in a chat app. Because chat is real-time, it subscribes to many event types to keep the list updated (new messages, updates, channel changes, presence, etc.).

That’s a lot of logic to reimplement. We recommend building on the SDK’s `ChannelList` even if you need heavy customization. It supports:

1. [Custom channel preview](#custom-channel-preview)
2. [Custom channel list wrapper](#custom-channel-list-wrapper)
3. [Custom channel list renderer](#custom-channel-list-renderer)
4. [Custom paginator](/chat/docs/sdk/react/v13/guides/channel-list-infinite-scroll/)

## Best Practices

- Use `ChannelList` as the base and override only the preview UI you need.
- Keep preview rendering fast to avoid sluggish navigation.
- Read channel state from `Preview` props (for example `channel`) instead of re-querying.
- Preserve selection handling so active channel updates stay consistent.
- Add timestamps or metadata only when it improves scanability.

This guide takes a deep dive into these customization options.

## Custom Channel Preview

A channel preview is a single item in the list. It should reflect current channel state and handle selection.

![](@chat-sdk/react/v13/_assets/channel-list-preview.png)

Customize previews by passing a component to [`Preview`](/chat/docs/sdk/react/v13/components/core-components/channel_list#preview/). `ChannelList` wraps each item in `ChannelPreview`, which handles events (new/updated/deleted messages). You can just read the latest state from props.

```tsx
<ChannelList Preview={CustomChannelPreview} />
// Don't forget to provide filter and sort options as well!
```

Let's implement a simple custom preview:

<Tabs>

</Tabs>

(See also the complete reference of [the available preview component props](/chat/docs/sdk/react/v13/components/utility-components/channel_preview_ui/).)

![](@chat-sdk/react/v13/_assets/channel-list-preview-custom.png)

The preview props are usually enough. If you need more data, read it from the channel state. In this example we add the timestamp of the latest message:

<Tabs>

</Tabs>

![](@chat-sdk/react/v13/_assets/channel-list-preview-timestamp.png)

One more thing we should add is the click event handler, which should change the
currently active channel. That's easy enough to do:

<Tabs>

</Tabs>

![](@chat-sdk/react/v13/_assets/channel-list-preview-selected.png)

We also add a class when the channel is active (by comparing the active channel ID with the current channel ID).

## Custom Channel List Wrapper

The channel list wrapper renders items and handles loading/error states. It’s a good place to add a custom loader or extra UI like a header/footer.

You can do this by providing a custom component in the [`List`](/chat/docs/sdk/react/v13/components/core-components/channel_list#list/) prop of the
`ChannelList` component. It will get a bunch of props from the parent
`ChannelList`, including a list of loaded channels, a loading flag, and an error
object (if any).

```tsx
<ChannelList List={CustomChannelList} />
// Don't forget to provide filter and sort options as well!
```

The simplest implementation of the custom channel list wrapper looks like this:

<Tabs>

</Tabs>

<gallery>

![Loading state](@chat-sdk/react/v13/_assets/channel-list-loading.png)

![Error state](@chat-sdk/react/v13/_assets/channel-list-error.png)

![Normal state](@chat-sdk/react/v13/_assets/channel-list-preview-selected.png)

</gallery>

If you need the channel array, use `loadedChannels`. It updates frequently, so you must opt in by setting [`sendChannelsToList`](/chat/docs/sdk/react/v13/components/core-components/channel_list#sendchannelstolist/) on `ChannelList`:

<Tabs>

</Tabs>

![](@chat-sdk/react/v13/_assets/channel-list-counter.png)

## Custom Channel List Renderer

By default, [`ChannelList`](/chat/docs/sdk/react/v13/components/core-components/channel_list/) renders previews in query order. To inject custom grouping or subheadings, provide a custom [`renderChannels`](/chat/docs/sdk/react/v13/components/core-components/channel_list#renderchannels/) function.

The function receives the loaded channels and a preview renderer. That renderer is the `Preview` component wrapped with `ChannelPreview` so event listeners are already wired. `renderChannels` runs only when the list is loaded and non-empty.

This example adds a separator between read and unread channels:

<Tabs>

</Tabs>

![](@chat-sdk/react/v13/_assets/channel-list-separator.png)


---

This page was last updated at 2026-04-21T07:55:45.463Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v13/guides/customization/channel_list_preview/](https://getstream.io/chat/docs/sdk/react/v13/guides/customization/channel_list_preview/).