Channel Preview
Each row of a ChannelList is a ChannelListItem. It reads the row's values from the channel's stores, such as the title, the last message and the unread count, and renders ChannelListItemUI, the row's look, with them as props. Channel list UI explains what each value is read from.
Best practices
- To change the look and keep the values, register your own
ChannelListItemUI. To change the whole row, register aListItem. - Keep a row light: it renders for every channel in the list.
- Use the props a row gets, such as
displayTitleandunread, rather than reading them from the channel again. They're reactive, andchannel.dataisn't. - Keep the row's clickable element a
<button>withrole="option"inside astr-chat__channel-list-item-containerelement. The list's arrow-key navigation moves between those. - To change only the avatar or the last-message line, override
AvatarorSummarizedMessagePreviewinstead of the whole row.
Basic usage
Register your component as ChannelListItemUI. This one renders the default row, and adds a label to frozen channels:
import type { PropsWithChildren } from "react";
import type { ChannelStateData } from "stream-chat";
import type { ChannelListItemUIProps } from "stream-chat-react";
import {
ChannelListItemUI,
useStateStore,
WithComponents,
} from "stream-chat-react";
const frozenSelector = ({ data }: ChannelStateData) => ({
frozen: !!data?.frozen,
});
const RowWithFrozenLabel = (props: ChannelListItemUIProps) => {
const { frozen } = useStateStore(props.channel.state, frozenSelector);
return (
<div className="channel-row">
<ChannelListItemUI {...props} />
{frozen && <span className="channel-row__label">Frozen</span>}
</div>
);
};
const overrides = { ChannelListItemUI: RowWithFrozenLabel };
export const WithFrozenLabels = ({ children }: PropsWithChildren) => (
<WithComponents overrides={overrides}>{children}</WithComponents>
);The Preview UI recipe builds a row from scratch.
Default preview behavior
The default ChannelListItemUI:
- is a
<button>withrole="option", andaria-selectedwhile its channel is open; - renders the
Avataroverride,ChannelAvatarby default, withdisplayImageand the members of a group channel; - shows
displayTitle, and a pin icon and a mute icon when the channel is pinned or muted; - shows the time of the previewed message with
ChannelListItemTimestamp, and an unread badge whenunreadis above 0; - renders the
SummarizedMessagePreviewoverride for the last-message line, with the sender and the delivery status of the user's own message; - renders the
ChannelListItemActionButtonsoverride after the button: mute, and a menu with archive, block, pin and leave. See Channel-list row actions; - calls
onSelectwhen clicked, if set. Otherwise it opens the channel withopenChannel(channel, { event }).
Props
ChannelListItem takes the props in the first table, and passes them on to ChannelListItemUI. ChannelListItemUI also gets the values in the second table, which ChannelListItem computes.
| Prop | Type | Default | Description |
|---|---|---|---|
channel |
Channel |
required | The row's channel. |
active |
boolean |
whether the channel is open | Whether the row is highlighted. ChannelListItem sets it from isChannelActive(channel.cid) unless you pass it. |
activeChannel |
Channel |
none | In the type, but nothing sets or reads it. |
className |
string |
none | Class name added to the row's button. |
onSelect |
(event: React.MouseEvent) => void |
none | Runs when the row is clicked, instead of opening the channel. |
previewedMessage |
LocalMessage |
the channel's latest message | The message the row previews. Search results pass the matched message. |
| Prop | Type | Description |
|---|---|---|
accessibleLabelConfig |
ChannelListItemLabelConfig |
Not set by ChannelListItem. Pass it from your own ChannelListItemUI to the default one, to change the row's accessible name: its parts, their order, the separator, or the whole label. |
displayImage |
string |
The channel's image. In a channel with two members and no image, the other member's image. |
displayTitle |
string |
The channel's name. Without one: the other member's name in a channel with two members, or two other members' names in a larger one. |
groupChannelDisplayInfo |
GroupChannelDisplayInfo |
The members to show in a group avatar. Its overflowCount is in the type, but the SDK leaves it undefined. |
messageDeliveryStatus |
MessageDeliveryStatus |
sent, delivered or read, for the user's own previewed message. undefined for someone else's message. |
muted |
boolean |
Whether the user muted the channel. |
pinned |
boolean |
Whether the user pinned the channel. |
unread |
number |
The user's unread messages in the channel. 0 while the channel is muted. |
Delivery status and summaries
These parts and helpers are exported, to build a row that matches the default one:
| Name | What it does |
|---|---|
ChannelListItemTimestamp |
The time of previewedMessage, formatted like the default row. |
SummarizedMessagePreview |
The last-message line. Takes latestMessage, messageDeliveryStatus and participantCount. |
useLatestMessagePreview(params) |
What SummarizedMessagePreview renders, as data: text, type, senderName and deliveryStatus. Takes the same params. |
useChannelPreviewInfo({ channel }) |
displayTitle, displayImage and groupChannelDisplayInfo, reactively. |
useChannelDisplayName(channel) |
displayTitle alone. |
getChannelDisplayImage(channel, currentUserId) |
displayImage, read once, not reactively. |
useChannelMembershipState(channel) |
The user's membership, with pinned_at and archived_at. |
useChannelListItemContext() |
{ channel }, for any component rendered inside a row. Throws outside one. |
useLatestMessagePreview returns a type for the kind of message, such as text, image, giphy, voice, poll or deleted. A /giphy message has the giphy type, not image. Its deliveryStatus adds sending to the three values of MessageDeliveryStatus.