import { ChannelDetail } from "stream-chat-react/channel-detail";
import "stream-chat-react/dist/css/index.css";
import "stream-chat-react/dist/css/channel-detail.css";Channel Detail
ChannelDetail is a composable surface for inspecting and managing a single channel. It renders channel info, members, pinned messages, shared media, and shared files, and adapts between a tabbed/docked layout (wide containers) and an inline hamburger-driven drawer (narrow containers).
It ships as a separate plugin entry point, stream-chat-react/channel-detail, with its own stylesheet. The component composes the generic SectionNavigator primitive with five default sections and provides the active channel to its children through ChannelDetailContext.
Installation
ChannelDetail is not exported from the package root. Import it (and the views, hooks, and primitives it ships with) from the plugin entry point, and load the plugin stylesheet alongside the core CSS:
Recommended patterns
The examples below fold the recommended practices into working code — read the inline comments for the rationale behind each one.
Render it in a sized side panel
ChannelDetail measures its container with a ResizeObserver and switches layout accordingly, so it needs a sized parent to lay out correctly. It also never reads the active channel from context — you pass it in, so you stay in control of which channel it inspects.
import { useChannelStateContext } from "stream-chat-react";
import { ChannelDetail } from "stream-chat-react/channel-detail";
const ChannelInfoPanel = () => {
// Pass `channel` explicitly — ChannelDetail does not pull it from context,
// so you decide which channel the surface inspects.
const { channel } = useChannelStateContext();
return (
// Give it a measurable, sized container. The ResizeObserver picks the
// layout from this width: wide → docked `tabs`, narrow → `inline` drawer.
<aside style={{ width: 360, height: "100%" }}>
<ChannelDetail channel={channel} />
</aside>
);
};With the five default sections, this renders Channel info, Members, Pinned messages, Photos & videos, and Files.
Open details from the channel header avatar
For the common "click the header avatar to open details in a modal" behavior, use AvatarWithChannelDetail rather than wiring a modal around ChannelDetail yourself.
import { ChannelHeader } from "stream-chat-react";
import { AvatarWithChannelDetail } from "stream-chat-react/channel-detail";
// No sizing or channel wiring needed here: the modal sizes the surface, and
// AvatarWithChannelDetail reads the active channel from ChannelStateContext.
<ChannelHeader Avatar={AvatarWithChannelDetail} />;Adjust the surface instead of rebuilding it
Customize through the sections prop or by overriding individual views — everything you don't replace keeps its built-in behavior, including the confirmation dialogs that gate destructive actions (leave/delete, block/unblock).
import {
ChannelDetail,
defaultChannelDetailSections,
} from "stream-chat-react/channel-detail";
// Start from the defaults and tweak — here, drop the Files section — instead
// of assembling the surface from scratch. The sections you keep retain their
// behavior, so destructive actions stay gated behind their confirmation dialogs.
const sections = defaultChannelDetailSections.filter(
(section) => section.id !== "channel-files",
);
<ChannelDetail channel={channel} sections={sections} />;Layout
ChannelDetail switches between two layouts based on its container width:
tabs— a docked navigation sidebar with the active section beside it (the default).inline— a single-column view with a hamburger button that opens the navigation as a drawer overlay.
The breakpoint is controlled by tabsLayoutMinWidth (default 640px). Below it, the component uses the inline layout. Set defaultLayout to choose the layout used before the container has been measured.
<ChannelDetail
channel={channel}
defaultLayout="inline"
tabsLayoutMinWidth={720}
/>UI Customization
Choose or reorder sections
Each section is a { id, NavButton, SectionContent } descriptor. Pass a sections array to add, remove, or reorder them. The plugin exports the default sections and the individual section descriptors so you can reuse them:
import {
ChannelDetail,
ChannelManagementView,
ChannelMembersView,
PinnedMessagesView,
ChannelManagementNavButton,
ChannelMembersNavButton,
PinnedMessagesNavButton,
} from "stream-chat-react/channel-detail";
const sections = [
{
id: "channel-info",
NavButton: ChannelManagementNavButton,
SectionContent: ChannelManagementView,
},
{
id: "channel-members",
NavButton: ChannelMembersNavButton,
SectionContent: ChannelMembersView,
},
{
id: "pinned-messages",
NavButton: PinnedMessagesNavButton,
SectionContent: PinnedMessagesView,
},
];
const App = ({ channel }) => (
<ChannelDetail channel={channel} sections={sections} />
);To replace the contents of a section while keeping its nav button, supply a custom SectionContent. A section's content component receives the current layout and can read the channel through useChannelDetailContext. See Views for the props each built-in view accepts.
Add a custom section
import type { SectionNavigatorSection } from "stream-chat-react/channel-detail";
const NotificationsSection: SectionNavigatorSection = {
id: "notifications",
NavButton: ({ select, selected }) => (
<button onClick={select} aria-pressed={selected}>
Notifications
</button>
),
SectionContent: () => <NotificationSettings />,
};
<ChannelDetail
channel={channel}
sections={[...defaultChannelDetailSections, NotificationsSection]}
/>;Reading the channel from descendants
ChannelDetail wraps its content in ChannelDetailProvider. Custom views and nav buttons can read the active channel with useChannelDetailContext:
import { useChannelDetailContext } from "stream-chat-react/channel-detail";
const MemberCount = () => {
const { channel } = useChannelDetailContext();
return <span>{channel.data?.member_count} members</span>;
};Calling useChannelDetailContext outside of ChannelDetail (or a ChannelDetailProvider) throws.
Props
ChannelDetail accepts every SectionNavigator prop except sections (whose shape is the same but whose default differs), plus the following.
| Name | Description | Type | Default |
|---|---|---|---|
channel | The channel to inspect and manage. Required. | Channel | - |
sections | The sections to render, each a { id, NavButton, SectionContent } descriptor. | SectionNavigatorSection[] | defaultChannelDetailSections |
defaultLayout | Layout used before the container is measured. | "tabs" | "inline" | "tabs" |
tabsLayoutMinWidth | Minimum container width (px) for the tabs layout; below it the inline layout is used. | number | 640 |
className | Additional class name applied to the root element. | string | - |
Exports
The plugin's main exports for this surface:
| Export | Description |
|---|---|
ChannelDetail | The main component. |
defaultChannelDetailSections | The five default section descriptors. |
ChannelManagementNavButton, ChannelMembersNavButton, PinnedMessagesNavButton, ChannelMediaNavButton, ChannelFilesNavButton | The default nav buttons for each section. |
ChannelDetailProvider | Provider that exposes the active channel. |
useChannelDetailContext | Hook returning { channel } from the nearest provider. |
The view components, search hooks, and primitives are documented separately in Views, SectionNavigator, and AvatarWithChannelDetail.