import { ChannelList, WithComponents } from "stream-chat-react";
const CustomChannelPreview = ({ latestMessagePreview }) => (
<span>{latestMessagePreview}</span>
);
<WithComponents overrides={{ ChannelListItemUI: CustomChannelPreview }}>
<ChannelList />
</WithComponents>;Channel Preview
ChannelListItemUI is the default row UI used by ChannelList. Replace it through WithComponents / ComponentContext when you need custom row rendering.
Best Practices
- Preserve the selection handler so active channel switching keeps working.
- Keep preview rendering lightweight because it runs for every item in the list.
- Prefer the provided
displayTitle,displayImage, andgroupChannelDisplayInfovalues over recomputing channel metadata yourself. - Use
latestMessagePreviewfor the preview text instead of rebuilding message summaries from scratch. - If you build summaries from
useLatestMessagePreview(), handle nativegiphymessages separately from ordinary images. - Override
Avatarseparately throughWithComponentsif only the channel image rendering needs to change. - Keep custom CSS aligned with the current preview structure and button semantics.
Basic Usage
To customize the row UI, register your component as the ChannelListItemUI override:
Default Preview Behavior
ChannelListItemUI:
- renders
ChannelAvatarby default, not the plainAvatarcomponent - uses
displayTitle,displayImage, andgroupChannelDisplayInfofromuseChannelPreviewInfo() - renders
SummarizedMessagePreviewfor the last-message summary - uses
ChannelListItemTimestampfor the timestamp - marks the selected row with
aria-pressed - renders
ChannelListItemActionButtons, which use a context menu plus archive or mute actions depending on channel type
Props
| Prop | Description | Type |
|---|---|---|
active | Whether the row channel is currently selected. | boolean |
activeChannel | The active channel from chat context. | Channel |
channel | The channel instance for the row. | Channel |
channelUpdateCount | Counter value used to force a rerender when the parent list wants to refresh previews. | number |
className | Custom class name merged onto the preview button. | string |
displayImage | Resolved image to display for the row. For direct messages, this can include the SDK's fallback to the other member's image. | string |
displayTitle | Resolved display title for the row. For direct messages and group channels, this can be synthesized from members. | string |
getLatestMessagePreview | Custom function to build the preview text. | (channel: Channel, t: TranslationContextValue["t"], userLanguage: TranslationContextValue["userLanguage"], isMessageAIGenerated: ChatContextValue["isMessageAIGenerated"]) => ReactNode |
groupChannelDisplayInfo | Resolved group-avatar data for channels with multiple visible members. | GroupChannelDisplayInfo |
lastMessage | The latest message currently used to build the row summary. | LocalMessage |
latestMessagePreview | Rendered preview of the latest message. | ReactNode |
messageDeliveryStatus | Delivery status for your own latest message. Use it when you replace the summary UI. | MessageDeliveryStatus |
muted | Whether the current user has muted the channel. | boolean |
onSelect | Custom click handler for the row. | (event: React.MouseEvent) => void |
setActiveChannel | Setter used by the default row click handler. | ChatContextValue["setActiveChannel"] |
unread | Unread message count for the channel. | number |
watchers | Watcher query options forwarded when activating the channel. | { limit?: number; offset?: number } |
If you need to change only the avatar rendering, override Avatar through WithComponents instead of expecting ChannelListItemUI to receive an Avatar prop.
Delivery Status And Summaries
If you build your own row, prefer reusing the SDK helpers that match the default preview:
ChannelListItemTimestampSummarizedMessagePreviewgetChannelDisplayImage(channel)useChannelDisplayName(channel)
That keeps custom previews aligned with the current channel title, avatar, timestamp, and delivery-status behavior without depending on removed standalone status-icon exports.
If you go lower-level and switch on useLatestMessagePreview().type, include a giphy case. Native giphy messages now resolve to their own preview type instead of being folded into image.