Channel Detail Shared Components
The channel details views and nav buttons are built from a few small components. stream-chat-react/channel-detail exports them, so sections and lists of your own can look and behave like the built-in ones.
import {
ChannelDetailEmptyList,
ChannelDetailListLoadingIndicator,
ChannelDetailNavButton,
ChannelDetailSearchInput,
} from "stream-chat-react/channel-detail";
import "stream-chat-react/dist/css/index.css";
import "stream-chat-react/dist/css/channel-detail.css";ChannelDetailNavButton
The button behind every built-in nav button. It renders a ListItemLayout as a button, marks the open section with aria-current="page", and opens its section when clicked. Use it as the NavButton of a custom section:
import { ChannelDetailNavButton } from "stream-chat-react/channel-detail";
import type { SectionNavigatorNavButtonProps } from "stream-chat-react/channel-detail";
const BellIcon = () => <span aria-hidden="true">🔔</span>;
export const NotificationsNavButton = (
props: SectionNavigatorNavButtonProps,
) => (
<ChannelDetailNavButton
{...props}
LeadingIcon={BellIcon}
title="Notifications"
/>
);ChannelDetailNavButton takes the SectionNavigatorNavButtonProps: sectionId, selected, select and the button props, which go to the button. Plus:
| Prop | Type | Default | Description |
|---|---|---|---|
LeadingIcon |
React.ComponentType |
required | The icon before the title. |
title |
string |
required | The section's name. |
ChannelDetailSearchInput
The search field of the member list, the add members view and the pinned messages view. It keeps its own value and calls onSearchChange on every change. Changing resetKey clears it. useChannelMembersSearch() returns a handleSearchChange and a searchInputResetKey made for it:
import {
ChannelDetailSearchInput,
useChannelMembersSearch,
} from "stream-chat-react/channel-detail";
// Render inside ChannelDetail.
export const MemberSearch = () => {
const { displayedMembers, handleSearchChange, searchInputResetKey } =
useChannelMembersSearch();
return (
<>
<ChannelDetailSearchInput
onSearchChange={handleSearchChange}
resetKey={searchInputResetKey}
/>
<ul>
{displayedMembers.map((member) => (
<li key={member.user_id}>{member.user?.name ?? member.user_id}</li>
))}
</ul>
</>
);
};| Prop | Type | Default | Description |
|---|---|---|---|
onSearchChange |
(query: string) => void |
required | Called with the field's value on every change. |
autoFocus |
boolean |
none | Focuses the field when it mounts. |
resetKey |
number |
none | Clears the field whenever it changes. |
Its placeholder and aria-label are the translation key common.search.ariaLabel, "Search". See Localization.
ChannelDetailEmptyList
What a list view shows when there is nothing to list: a search icon above its children.
import { ChannelDetailEmptyList } from "stream-chat-react/channel-detail";
export const NoResults = () => (
<ChannelDetailEmptyList>No results found</ChannelDetailEmptyList>
);It takes children only. Three views have their own empty state, with their own text and no props: ChannelMediaEmptyList, ChannelFilesEmptyList and PinnedMessagesEmptyList. The last shows a pin icon with "No pinned messages" and "Pin a message to see it here".
ChannelDetailListLoadingIndicator
The footer of a paginated list. It reads a search source's state and shows a LoadingIndicator only while the source is loading and has another page. Put it after a list fed by one of the search hooks:
import {
ChannelDetailListLoadingIndicator,
useChannelFilesSearch,
} from "stream-chat-react/channel-detail";
// Render inside ChannelDetail.
export const FileNames = () => {
const { channelFilesSearchSource, fileItems } = useChannelFilesSearch();
return (
<>
<ul>
{fileItems.map((item) => (
<li key={item.id}>{item.attachment.title}</li>
))}
</ul>
<ChannelDetailListLoadingIndicator
searchSource={channelFilesSearchSource}
/>
</>
);
};| Prop | Type | Default | Description |
|---|---|---|---|
searchSource |
SearchSource<T> |
required | The source whose loading state it shows. |
Its props type is exported as ChannelMembersViewListFooterProps<T>.