# Channel details lists

> **Info:** This is release candidate documentation for **Stream Chat React Native SDK v10**. For the latest stable version, see the [latest version (v9)](https://getstream.io/chat/docs/sdk/react-native/).

Channel details has five lists, the member list, the add members form, and the pinned messages, photos and videos, and files lists. `ChannelDetails` opens each in a modal, and each is exported so a screen of your own can render it. This page lists their parts, override keys and props. [ChannelDetails](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-details/channel-details/) covers the screen that opens them.

## Best practices

- Render a list inside a `ChannelDetailsContextProvider` for the channel. It reads the channel from there, and renders nothing until the channel has a `cid`.
- Give the list a container with a height, such as a screen with `flex: 1`. The lists scroll inside it.
- Replace a row through its override key, such as `PinnedMessageItem`, rather than the whole list. The list keeps its loading, paging, search and empty states.
- To change what a list loads, pass your own search source as `searchSource`. [Channel details contexts](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-details/channel-details-contexts/) shows the default sources.

## How the lists load

Each list loads from a search source of `stream-chat`, which it creates when it mounts:

| List                    | Override key            | Opened from                                         | Loads                                                                                    |
| ----------------------- | ----------------------- | --------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| `ChannelMemberList`     | `ChannelMemberList`     | **View all** in the members section                 | The channel's members, by name, with a `ChannelMemberSearchSource`                       |
| `ChannelAddMembersForm` | `ChannelAddMembersForm` | **Add**, in the members section and the member list | Users, by name, with a `UserSearchSource`                                                |
| `PinnedMessageList`     | `PinnedMessageList`     | **Pinned Messages**                                 | The channel's pinned messages, with a `MessageSearchSource`, searched by text            |
| `MediaList`             | `MediaList`             | **Photos & Videos**                                 | The channel's messages with images or videos, newest first, with a `MessageSearchSource` |
| `FileAttachmentList`    | `FileAttachmentList`    | **Files**                                           | The channel's messages with files or audio, newest first, with a `MessageSearchSource`   |

Each source loads 25 items a page, and the list loads the next page when it's scrolled near its end, with a spinner at the bottom meanwhile. The member list, the add members form and the pinned messages list have a `SearchInput` that searches as the user types. The first load shows a skeleton. The pinned messages, photos and videos, and files lists show `EmptyList` when they have nothing, and the pinned messages list shows `EmptySearchResult` for a search that matched nothing. The member list and the add members form show `EmptySearchResult` whenever they're empty.

The sources are a snapshot. They don't change as events arrive, so a message pinned while the list is open shows the next time it opens. The member list is the exception. It loads its first page again when the channel's member count changes, while no search is typed, so members added from it show at once.

When a query fails, the list publishes an error notification, such as `api:channel:query-members:failed`, to a `NotificationList` of its own. Each list is its own notification target in the `channel-details` panel.

## Members

### ChannelMemberList

The searchable list of the channel's members, each through the `ChannelMemberItem` key. Pressing a member opens the `ChannelMemberActionsSheet` key for them.

| Prop                      | Type                                            | Default                               | Description                                                                                     |
| ------------------------- | ----------------------------------------------- | ------------------------------------- | ----------------------------------------------------------------------------------------------- |
| `searchSource`            | `ChannelMemberSearchSource`                     | the channel's members, sorted by name | The source to load from.                                                                        |
| `searchInputProps`        | `SearchInputProps`                              |                                       | Passed to the `SearchInput`, after the list's own props, so `onChangeText` replaces the search. |
| `additionalFlatListProps` | `Partial<FlatListProps<ChannelMemberResponse>>` |                                       | Passed to the `FlatList`, after the list's own props.                                           |

### ChannelMemberItem

A member row shows a `UserAvatar`, with a presence dot while the user is online, the name, or "You" for the current user, the activity status from `useUserActivityStatus`, a mute icon while the user is muted, and the `RoleList` key with the member's roles. With `onPress` it's a button; without one, a plain row.

| Prop             | Type                                      | Default           | Description                                                                                                         |
| ---------------- | ----------------------------------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------- |
| `member`         | `ChannelMemberResponse`                   | required          | The member. A member without a `user` renders nothing.                                                              |
| `onPress`        | `(member: ChannelMemberResponse) => void` |                   | Makes the row pressable.                                                                                            |
| `size`           | `ChannelMemberItemSize`                   | `'sm'`            | `'sm'`, a list row with an `md` avatar, or `'lg'`, a header with an `lg` avatar, as at the top of the member sheet. |
| `getMemberRoles` | `GetMemberRoles`                          | the default roles | `({ channel, defaultRoleLabels, member, t }) => roles`, the roles to show. `[]` shows none.                         |
| `testID`         | `string`                                  |                   | Set on the row.                                                                                                     |

The default roles are Owner for the channel's creator, Admin for a user whose role is `admin`, and Moderator for a member whose `channel_role` is `channel_moderator`. [Custom member roles](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/channel-details/custom-member-roles/) shows others.

### RoleList and RoleItem

`RoleList` renders a `RoleItem` key for each role, and nothing without roles. `RoleItem` is a pill with the role's `label`, in the brand colors for the `owner` key and in neutral colors otherwise.

| Prop    | Type          | Default  | Description                       |
| ------- | ------------- | -------- | --------------------------------- |
| `roles` | `RoleLabel[]` | required | The roles, each `{ key, label }`. |

`RoleItemProps`:

| Prop        | Type                   | Default  | Description                            |
| ----------- | ---------------------- | -------- | -------------------------------------- |
| `role`      | `RoleLabel`            | required | The role.                              |
| `textStyle` | `StyleProp<TextStyle>` |          | Applied to the label, after the theme. |
| `viewStyle` | `StyleProp<ViewStyle>` |          | Applied to the pill, after the theme.  |

### ChannelMemberActionsSheet

A bottom sheet with the member as a `lg` `ChannelMemberItem` and the member's actions as `ChannelDetailsActionItem` rows. Pressing an action runs it and closes the sheet. The actions come from `useChannelMemberActionItems`: mute or unmute and block or unblock the user, and remove the member with the `update-channel-members` capability. The current user's own sheet has no actions.

| Prop                          | Type                          | Default  | Description                                                                                                                                                |
| ----------------------------- | ----------------------------- | -------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `member`                      | `ChannelMemberResponse`       | required | The member.                                                                                                                                                |
| `visible`                     | `boolean`                     | required | Whether the sheet is open.                                                                                                                                 |
| `onClose`                     | `() => void`                  | required | Called when the sheet closes, and after an action.                                                                                                         |
| `getChannelMemberActionItems` | `GetChannelMemberActionItems` |          | `({ context, defaultItems }) => items`, the actions to show. See [Member actions](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/actions/#member-actions). |

## Adding members

### ChannelAddMembersButton

Renders **Add**, or a user-plus icon, when the user has the `update-channel-members` capability, and nothing otherwise. Pressing it opens the `ChannelAddMembersForm` key in a modal.

| Prop      | Type                   | Default  | Description                                                            |
| --------- | ---------------------- | -------- | ---------------------------------------------------------------------- |
| `variant` | `'icon' \| 'text'`     | `'text'` | An outlined **Add** button, or an icon-only button.                    |
| `onPress` | `() => void`           |          | Called in place of opening the form. The button then renders no modal. |
| `style`   | `ButtonProps['style']` |          | Passed to the `Button`.                                                |
| `testID`  | `string`               |          | Passed to the `Button`.                                                |

The members section renders it with `variant="text"`, and the header of the member list with `variant="icon"`.

### ChannelAddMembersForm

Wraps its parts in a `ChannelAddMembersProvider`, and renders the `ChannelAddMembersFormHeader` key, the `ChannelAddMembersFormContent` key and a `NotificationList`.

| Prop           | Type               | Default               | Description                                                                            |
| -------------- | ------------------ | --------------------- | -------------------------------------------------------------------------------------- |
| `onClose`      | `() => void`       | required              | Called by the close button, and after members are added.                               |
| `searchSource` | `UserSearchSource` | users, sorted by name | The source to load from. It's used as it is, so activate it and set its sort yourself. |

### ChannelAddMembersFormHeader

Close, "Add Members", and a confirm button. The confirm button is enabled while at least one user is selected. It calls `submit()` of the add members context, which adds the selected users with `Channel.addMembers({ members })`, and closes the form when it succeeds.

| Prop      | Type         | Default  | Description                                              |
| --------- | ------------ | -------- | -------------------------------------------------------- |
| `onClose` | `() => void` | required | Called by the close button, and after members are added. |

### ChannelAddMembersFormContent

The `SearchInput` and the list of users, each an `AddMemberSearchResultItem`. It searches with an empty query when it mounts, so the list starts with every user the source returns.

| Prop                      | Type                                   | Default | Description                                           |
| ------------------------- | -------------------------------------- | ------- | ----------------------------------------------------- |
| `additionalFlatListProps` | `Partial<FlatListProps<UserResponse>>` |         | Passed to the `FlatList`, after the list's own props. |

### AddMemberSearchResultItem

A user row with a `UserAvatar`, the name and a `SelectionCircle`. Pressing it calls `onPress`, which the form uses to toggle the user in its selection. A user who is already a member shows "Already a member" and can't be pressed. It has no override key, because `ChannelAddMembersFormContent` renders it directly.

| Prop      | Type                           | Default  | Description                     |
| --------- | ------------------------------ | -------- | ------------------------------- |
| `user`    | `UserResponse`                 | required | The user.                       |
| `onPress` | `(user: UserResponse) => void` | required | Called when the row is pressed. |

It reads the selection from `useChannelAddMembersContext()`, so it renders inside a `ChannelAddMembersProvider`.

## Pinned messages

### PinnedMessageList

The searchable list of the channel's pinned messages, each through the `PinnedMessageItem` key. While the channel has no pinned messages, it shows an `EmptyList` and no search field.

| Prop                      | Type                                      | Default                       | Description                                              |
| ------------------------- | ----------------------------------------- | ----------------------------- | -------------------------------------------------------- |
| `searchSource`            | `MessageSearchSource`                     | the channel's pinned messages | The source to load from.                                 |
| `searchInputProps`        | `SearchInputProps`                        |                               | Passed to the `SearchInput`, after the list's own props. |
| `additionalFlatListProps` | `Partial<FlatListProps<MessageResponse>>` |                               | Passed to the `FlatList`, after the list's own props.    |

### PinnedMessageItem

A row with the sender's `UserAvatar`, the sender's name, and the message's preview and time through the `ChannelPreviewLastMessage` and `ChannelPreviewStatus` keys. It shows the message's translation in the user's language when there is one. It isn't pressable. To jump to the message, override the key with a row that navigates, as [Pinned messages](https://getstream.io/chat/docs/sdk/react-native/v10/ui/layout/moving-between-channels-threads-and-messages/#pinned-messages) shows.

| Prop                | Type                                                   | Default                      | Description                                 |
| ------------------- | ------------------------------------------------------ | ---------------------------- | ------------------------------------------- |
| `channel`           | `Channel`                                              | required                     | The channel.                                |
| `message`           | `MessageResponse`                                      | required                     | The pinned message.                         |
| `formatMessageDate` | `ChannelPreviewStatusProps['formatLatestMessageDate']` | the channel preview's format | `(date: Date) => string`, formats the time. |

The list passes `channel` and `message`.

## Photos and videos

### MediaList

A grid of three columns, one `MediaItem` key per image or video attachment, from `useMediaList`. Pressing an image or a video opens the image gallery on it, with every loaded message to swipe through. Without a video player installed, pressing a video opens its URL instead.

| Prop                      | Type                                | Default                                                    | Description                                           |
| ------------------------- | ----------------------------------- | ---------------------------------------------------------- | ----------------------------------------------------- |
| `searchSource`            | `MessageSearchSource`               | the channel's messages with images or videos, newest first | The source to load from.                              |
| `additionalFlatListProps` | `Partial<FlatListProps<MediaTile>>` |                                                            | Passed to the `FlatList`, after the list's own props. |

It opens the gallery through `ImageGalleryContext` and `OverlayContext`, so it renders inside `OverlayProvider`. On a screen of your own, `OverlayProvider`'s gallery shows over it.

### MediaItem

A square tile with the attachment's thumbnail, resized through the CDN to the tile's size, the sender's `sm` `UserAvatar`, and, for a video, its duration.

| Prop         | Type                                     | Default  | Description                                                         |
| ------------ | ---------------------------------------- | -------- | ------------------------------------------------------------------- |
| `attachment` | `Attachment`                             | required | The image or video attachment.                                      |
| `message`    | `MessageResponse`                        | required | Its message.                                                        |
| `size`       | `number`                                 | required | The side of the tile, in points.                                    |
| `onPress`    | `(params: MediaItemPressParams) => void` |          | Called when the tile is pressed. Without it, the tile does nothing. |

`MediaItemPressParams` is `{ attachment, message, requesterNode }`. `requesterNode` is the tile's native handle, for the gallery's `openImageGallery()`.

## Files

### FileAttachmentList

A list of the file and audio attachments, under a header for each month, from `useFileAttachmentListSections`. Each attachment renders through the `FileAttachmentItem` key, and each header through `FileAttachmentListSectionHeader`, which has no override key. The headers stick to the top while their month scrolls.

| Prop                         | Type                                                                   | Default                                                  | Description                                              |
| ---------------------------- | ---------------------------------------------------------------------- | -------------------------------------------------------- | -------------------------------------------------------- |
| `searchSource`               | `MessageSearchSource`                                                  | the channel's messages with files or audio, newest first | The source to load from.                                 |
| `additionalSectionListProps` | `Partial<SectionListProps<FileAttachmentTile, FileAttachmentSection>>` |                                                          | Passed to the `SectionList`, after the list's own props. |

### FileAttachmentItem

A row with the file's icon, name and size. Pressing it opens the attachment's `asset_url`.

| Prop         | Type                                              | Default           | Description                                                         |
| ------------ | ------------------------------------------------- | ----------------- | ------------------------------------------------------------------- |
| `attachment` | `Attachment`                                      | required          | The file or audio attachment.                                       |
| `message`    | `MessageResponse`                                 | required          | Its message.                                                        |
| `onPress`    | `(params: FileAttachmentItemPressParams) => void` | opens `asset_url` | Called in place of opening the URL, with `{ attachment, message }`. |

### FileAttachmentListSectionHeader

| Prop    | Type     | Default  | Description                                |
| ------- | -------- | -------- | ------------------------------------------ |
| `title` | `string` | required | The section's title, such as "March 2026". |

## Loading skeletons

The lists show these while their first page loads. They take no props, have no override key, and are styled by the theme key in brackets: `MemberListLoadingSkeleton` (`memberListSkeleton`), `UserListLoadingSkeleton` (`userListSkeleton`), `PinnedMessageListLoadingSkeleton` (`pinnedMessageListSkeleton`), `FileAttachmentListLoadingSkeleton` (`fileAttachmentListSkeleton`) and `MediaListLoadingSkeleton`.

## Theming

The theme's `channelDetails` key styles the lists and rows: `memberList`, `memberItem`, `roleList`, `roleItem`, `memberActionsSheet`, `addMembers`, `pinnedMessageList`, `pinnedMessageItem`, `mediaList`, `mediaItem`, `fileAttachmentList` and `fileAttachmentItem`. See [Theme object](https://getstream.io/chat/docs/sdk/react-native/v10/reference/theme/theme-object/#channeldetails).

## Example

A files screen of your own, which opens files in your viewer:

```tsx title="src/ChannelFilesScreen.tsx"
import { View } from "react-native";
import type { Channel as StreamChannel } from "stream-chat";
import {
  ChannelDetailsContextProvider,
  FileAttachmentItem,
  FileAttachmentList,
  WithComponents,
} from "stream-chat-react-native";
import type {
  ComponentOverrides,
  FileAttachmentItemProps,
} from "stream-chat-react-native";

type Props = {
  channel: StreamChannel;
  openFile: (url: string) => void;
};

export const ChannelFilesScreen = ({ channel, openFile }: Props) => {
  const FileRow = (props: FileAttachmentItemProps) => (
    <FileAttachmentItem
      {...props}
      onPress={({ attachment }) => {
        if (attachment.asset_url) openFile(attachment.asset_url);
      }}
    />
  );
  const overrides: ComponentOverrides = { FileAttachmentItem: FileRow };

  return (
    <ChannelDetailsContextProvider channel={channel}>
      <WithComponents overrides={overrides}>
        <View style={{ flex: 1 }}>
          <FileAttachmentList />
        </View>
      </WithComponents>
    </ChannelDetailsContextProvider>
  );
};
```

`WithComponents` reads `overrides` when it mounts, so the row keeps the `openFile` of the first render. Pass a function that stays the same, such as one from `useCallback` or your navigator.

## Exports

| Export                                                                                                                                                      | What it is        |
| ----------------------------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| `ChannelMemberList`, `ChannelMemberItem`, `ChannelMemberActionsSheet`, `RoleList`, `RoleItem`                                                               | The members       |
| `ChannelAddMembersButton`, `ChannelAddMembersForm`, `ChannelAddMembersFormHeader`, `ChannelAddMembersFormContent`, `AddMemberSearchResultItem`              | Adding members    |
| `PinnedMessageList`, `PinnedMessageItem`                                                                                                                    | Pinned messages   |
| `MediaList`, `MediaItem`                                                                                                                                    | Photos and videos |
| `FileAttachmentList`, `FileAttachmentItem`, `FileAttachmentListSectionHeader`                                                                               | Files             |
| `MemberListLoadingSkeleton`, `UserListLoadingSkeleton`, `PinnedMessageListLoadingSkeleton`, `MediaListLoadingSkeleton`, `FileAttachmentListLoadingSkeleton` | Loading states    |

The props types are exported with the components' names plus `Props`, as `ChannelMemberListProps`, except for the skeletons. `ChannelMemberItemSize`, `RoleLabel`, `GetMemberRoles`, `MediaItemPressParams`, `FileAttachmentItemPressParams`, `MediaTile`, `FileAttachmentTile` and `FileAttachmentSection` are exported too.

## Related hooks

| Hook                                                                                                                                                                              | Returns                                                       |
| --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------- |
| `useMemberRoles(member, getMemberRoles?)`                                                                                                                                         | the roles of a member row                                     |
| `useChannelMemberActionItems({ channel, member })`                                                                                                                                | the actions of the member sheet                               |
| `useUserActivityStatus(user)`                                                                                                                                                     | "Online", when the user was last active, or "Offline"         |
| `useMediaList(messages)`                                                                                                                                                          | one tile per image or video attachment                        |
| `useFileAttachmentListSections(messages)`                                                                                                                                         | the file and audio attachments, by month                      |
| `useChannelMemberListContext()`, `useChannelAddMembersContext()`, `useChannelPinnedMessageListContext()`, `useChannelMediaListContext()`, `useChannelFileAttachmentListContext()` | the search source of each list, and the add members selection |

They're on [Channel details hooks](https://getstream.io/chat/docs/sdk/react-native/v10/reference/hooks/channel-details-hooks/). The contexts are on [Channel details contexts](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-details/channel-details-contexts/).

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-details/channel-details-lists/](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel-details/channel-details-lists/).