Channel details and members
Channel details is a panel with everything about one channel: its info and settings, its members, its pinned messages, and the photos, videos and files shared in it. It ships as its own entry point, stream-chat-react/channel-detail. This page covers what users can do there and what each part calls in the state layer. How the panel opens and how its sections are laid out is on Channel UI.
What users get
The user clicks the avatar in the header of the "Design" channel. A panel opens with five sections:
- Channel info shows the channel's avatar and name, and how many members it has and how many are online. Edit changes the name and the image. A switch mutes the channel. Below it are Leave chat and Delete chat. In a direct message channel the section shows whether the other person is online, and adds a switch to mute them and a Block user button. It has no Leave chat there.
- Members lists the members with their role (Admin, Moderator or Owner) and whether they're online or when they were last active. A search field narrows the list, and Add finds users to add. Clicking a member opens their profile, with Send direct message, Mute user, Block user and Remove user.
- Pinned messages lists the channel's pinned messages, with a search field. Clicking one closes the panel and jumps to the message in the channel.
- Photos & videos shows the images and videos shared in the channel as a grid.
- Files lists the files and audio shared in the channel, grouped by month.
Leaving, deleting, blocking and removing a member ask the user to confirm first. Each action confirms its result with a notification, such as "User removed".
How it works across the layers
State: what each section calls
Every section works on the channel it was given, through the state layer:
| Section | What it reads | What it calls |
|---|---|---|
| Channel info | channel.state: the channel data, members, membership and mute status |
Channel.updatePartial() to save the name and image, Channel.uploadImage(), Channel.mute() and Channel.unmute(), Channel.removeMembers() to leave, Channel.delete() |
| Members | A ChannelMemberSearchSource for the list, which queries the channel's members. A UserSearchSource for adding |
Channel.addMembers({ members: userIds }), Channel.removeMembers({ members: [userId] }) |
| Member profile | The member, and the user's mute and block lists | client.moderation.mute() and client.moderation.unmute(), client.blockUser() and client.unblockUser(). Send direct message gets the channel with client.channel() and watches it |
| Pinned messages | A MessageSearchSource limited to this channel and pinned: true |
channel.messagePaginator.jumpToMessage() on the selected message |
| Photos & videos | A MessageSearchSource limited to this channel and to image and video attachments |
|
| Files | A MessageSearchSource limited to this channel and to file and audio attachments |
In a direct message channel, Channel info mutes and blocks the other member with the same calls as the member profile.
The lists in Members, Pinned messages, Photos & videos and Files come from search sources. Members and Pinned messages query once the channel has members or pinned messages, and Photos & videos and Files query when the section opens. Members, Pinned messages and Files load the next page as the user scrolls; Photos & videos pages with Previous and Next buttons. Search sources explains how they load.
The state doesn't change before the server answers. The channel's data, its members and the user's mute and block lists change when the response or the server's event arrives. The mute switches are the one place the UI runs ahead: a switch flips at once, sends its request a second after the last click, and flips back if the request fails. What channels and threads hold lists the fields and the events that change them.
UI: the panel
AvatarWithChannelDetail renders the channel avatar as a button, usually as the ChannelHeader avatar. It reads the channel with useChannel(), so it renders inside a Channel. Clicking it opens ChannelDetail in a modal: the Modal override, by default the SDK's GlobalModal. The button is disabled until the channel exists on the server, because the details are loaded from there.
ChannelDetail takes the channel as its channel prop and gives it to the sections through ChannelDetailContext. Its sections are a section navigator: the list of sections beside the open one when the panel is 640px wide or wider, and one section at a time when it's narrower. Render it inside a Channel for the same channel: the Channel info section reads the online status from the channel in context, and throws without one.
Two actions leave the panel and open a channel: Send direct message and selecting a pinned message. They open the channel with openChannel from useWorkspaceNavigation(), so they need ChatView or a WorkspaceNavigationProvider of your own. Moving between channels, threads and messages covers moving around inside the panel and out of it.
Turning it on or off
Channel details is off by default: the header's avatar is a plain channel avatar. To turn it on, import the entry point and its stylesheet, and pass AvatarWithChannelDetail to the header:
import type { Channel as ChannelType } from "stream-chat";
import {
Channel,
ChannelHeader,
MessageComposer,
MessageList,
} from "stream-chat-react";
import { AvatarWithChannelDetail } from "stream-chat-react/channel-detail";
import "stream-chat-react/dist/css/index.css";
import "stream-chat-react/dist/css/channel-detail.css";
export const ChannelWithDetails = ({ channel }: { channel: ChannelType }) => (
<Channel channel={channel}>
<ChannelHeader Avatar={AvatarWithChannelDetail} />
<MessageList />
<MessageComposer />
</Channel>
);To show the details in a panel of your own instead of a modal, render <ChannelDetail channel={channel} /> there, inside the same Channel.
Who sees which action depends on the user's capabilities in the channel, which the server derives from their roles and the channel type's permissions:
| Action | Shown when |
|---|---|
| Edit | update-channel |
| Mute chat | mute-channel |
| Mute user, in Channel info | A direct message channel with another member |
| Block user, in Channel info | A direct message channel with another member, and ban-channel-members |
| Leave chat | A group channel, and leave-channel |
| Delete chat | delete-channel |
| Add, in Members | update-channel-members |
| Remove user | update-channel-members, on another member |
| Send direct message, Mute user and Block user, in a member profile | Another member |
A direct message channel here is one with a single member, or with two members of which the user is one. Change capabilities on the server; see Permissions reference.
Customizing
Choosing the sections
ChannelDetail takes sections, the sections to show in order. defaultChannelDetailSections is the default list, with the ids channel-info, channel-members, pinned-messages, channel-media and channel-files. This header opens details without the media and files sections:
import { ChannelHeader } from "stream-chat-react";
import {
AvatarWithChannelDetail,
ChannelDetail,
defaultChannelDetailSections,
} from "stream-chat-react/channel-detail";
import type {
AvatarWithChannelDetailProps,
ChannelDetailProps,
} from "stream-chat-react/channel-detail";
const sections = defaultChannelDetailSections.filter(
({ id }) => id !== "channel-media" && id !== "channel-files",
);
const ChannelDetailWithoutMedia = (props: ChannelDetailProps) => (
<ChannelDetail {...props} sections={sections} />
);
const DetailsAvatar = (props: AvatarWithChannelDetailProps) => (
<AvatarWithChannelDetail
{...props}
ChannelDetail={ChannelDetailWithoutMedia}
/>
);
// Render inside a Channel.
export const DetailsHeader = () => <ChannelHeader Avatar={DetailsAvatar} />;A section is { id, NavButton, SectionContent }. To add one of your own, or replace what a section shows, see Channel Detail.
Uploading the channel image to your own storage
By default, Edit uploads a new channel image with Channel.uploadImage(), to Stream's CDN. ChannelManagementView, the Channel info section, takes uploadImage: a function that gets the file and returns the image URL to save:
import {
ChannelManagementView,
defaultChannelDetailSections,
} from "stream-chat-react/channel-detail";
import type {
SectionNavigatorSection,
SectionNavigatorSectionContentProps,
} from "stream-chat-react/channel-detail";
const uploadToOwnStorage = async (file: File) => {
const body = new FormData();
body.append("file", file);
const response = await fetch("/api/uploads", { body, method: "POST" });
const { url } = (await response.json()) as { url: string };
return url;
};
const ChannelInfo = (props: SectionNavigatorSectionContentProps) => (
<ChannelManagementView {...props} uploadImage={uploadToOwnStorage} />
);
// Pass these to ChannelDetail as `sections`, as in the example above.
export const sections: SectionNavigatorSection[] =
defaultChannelDetailSections.map((section) =>
section.id === "channel-info"
? { ...section, SectionContent: ChannelInfo }
: section,
);The name and the image are saved with Channel.updatePartial(), as custom.name and custom.image.
Changing the actions
The actions in Channel info, in a member profile and in the members header are action sets. Channel details actions shows how to remove, add and replace them, and which filter each one keeps.
Adding members with history hidden
The Add view in Members adds the chosen users with Channel.addMembers({ members: userIds }), so they see the channel's whole history. To hide it, add members from your own UI with the history options; see History visibility for new members.
Reference
- Channel Detail: the
ChannelDetailprops, sections and exports. - Avatar with Channel Detail: the
AvatarWithChannelDetailprops. - Section Navigator: the navigator and its layouts.
- Channel Detail Views: each section's view, its props and its search hook.
- Channel Detail Shared Components: the parts the views share.
- Channel and channel state:
addMembers,removeMembers,queryMembers,updatePartialand the other channel methods.