Info:
This is release candidate documentation for Stream Chat React SDK v15. For the latest stable version, see the latest version (v14).

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:

src/ChannelWithDetails.tsx
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:

src/DetailsHeader.tsx
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:

src/channelInfoSection.tsx
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