# Channel Preview

Each row of a [`ChannelList`](https://getstream.io/chat/docs/sdk/react/component-reference/channel-list/channellist/) is a `ChannelListItem`. It reads the row's values from the channel's stores, such as the title, the last message and the unread count, and renders `ChannelListItemUI`, the row's look, with them as props. [Channel list UI](https://getstream.io/chat/docs/sdk/react/ui/components/channel-list-ui/#channel-previews) explains what each value is read from.

## Best practices

- To change the look and keep the values, register your own `ChannelListItemUI`. To change the whole row, register a `ListItem`.
- Keep a row light: it renders for every channel in the list.
- Use the props a row gets, such as `displayTitle` and `unread`, rather than reading them from the channel again. They're reactive, and `channel.data` isn't.
- Keep the row's clickable element a `<button>` with `role="option"` inside a `str-chat__channel-list-item-container` element. The list's arrow-key navigation moves between those.
- To change only the avatar or the last-message line, override `Avatar` or `SummarizedMessagePreview` instead of the whole row.

## Basic usage

Register your component as `ChannelListItemUI`. This one renders the default row, and adds a label to frozen channels:

```tsx
import type { PropsWithChildren } from "react";
import type { ChannelStateData } from "stream-chat";
import type { ChannelListItemUIProps } from "stream-chat-react";
import {
  ChannelListItemUI,
  useStateStore,
  WithComponents,
} from "stream-chat-react";

const frozenSelector = ({ data }: ChannelStateData) => ({
  frozen: !!data?.frozen,
});

const RowWithFrozenLabel = (props: ChannelListItemUIProps) => {
  const { frozen } = useStateStore(props.channel.state, frozenSelector);

  return (
    <div className="channel-row">
      <ChannelListItemUI {...props} />
      {frozen && <span className="channel-row__label">Frozen</span>}
    </div>
  );
};

const overrides = { ChannelListItemUI: RowWithFrozenLabel };

export const WithFrozenLabels = ({ children }: PropsWithChildren) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);
```

The [Preview UI recipe](https://getstream.io/chat/docs/sdk/react/ui-cookbooks/channel-list/preview-ui/) builds a row from scratch.

## Default preview behavior

The default `ChannelListItemUI`:

- is a `<button>` with `role="option"`, and `aria-selected` while its channel is open;
- renders the `Avatar` override, `ChannelAvatar` by default, with `displayImage` and the members of a group channel;
- shows `displayTitle`, and a pin icon and a mute icon when the channel is pinned or muted;
- shows the time of the previewed message with `ChannelListItemTimestamp`, and an unread badge when `unread` is above 0;
- renders the `SummarizedMessagePreview` override for the last-message line, with the sender and the delivery status of the user's own message;
- renders the `ChannelListItemActionButtons` override after the button: mute, and a menu with archive, block, pin and leave. See [Channel-list row actions](https://getstream.io/chat/docs/sdk/react/ui/components/actions/#channel-list-item-actions);
- calls `onSelect` when clicked, if set. Otherwise it opens the channel with `openChannel(channel, { event })`.

## Props

`ChannelListItem` takes the props in the first table, and passes them on to `ChannelListItemUI`. `ChannelListItemUI` also gets the values in the second table, which `ChannelListItem` computes.

| Prop               | Type                                | Default                      | Description                                                                                                       |
| ------------------ | ----------------------------------- | ---------------------------- | ----------------------------------------------------------------------------------------------------------------- |
| `channel`          | `Channel`                           | required                     | The row's channel.                                                                                                |
| `active`           | `boolean`                           | whether the channel is open  | Whether the row is highlighted. `ChannelListItem` sets it from `isChannelActive(channel.cid)` unless you pass it. |
| `className`        | `string`                            | none                         | Class name added to the row's button.                                                                             |
| `onSelect`         | `(event: React.MouseEvent) => void` | none                         | Runs when the row is clicked, instead of opening the channel.                                                     |
| `previewedMessage` | `LocalMessage`                      | the channel's latest message | The message the row previews. Search results pass the matched message.                                            |

| Prop                      | Type                         | Description                                                                                                                                                                                 |
| ------------------------- | ---------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `accessibleLabelConfig`   | `ChannelListItemLabelConfig` | Not set by `ChannelListItem`. Pass it from your own `ChannelListItemUI` to the default one, to change the row's accessible name: its parts, their order, the separator, or the whole label. |
| `displayImage`            | `string`                     | The channel's image. In a channel with two members and no image, the other member's image.                                                                                                  |
| `displayTitle`            | `string`                     | The channel's name. Without one: the other member's name in a channel with two members, or two other members' names in a larger one.                                                        |
| `groupChannelDisplayInfo` | `GroupChannelDisplayInfo`    | The members to show in a group avatar. Its `overflowCount` is in the type, but the SDK leaves it `undefined`.                                                                               |
| `messageDeliveryStatus`   | `MessageDeliveryStatus`      | `sent`, `delivered` or `read`, for the user's own previewed message. `undefined` for someone else's message.                                                                                |
| `muted`                   | `boolean`                    | Whether the user muted the channel.                                                                                                                                                         |
| `pinned`                  | `boolean`                    | Whether the user pinned the channel.                                                                                                                                                        |
| `unread`                  | `number`                     | The user's unread messages in the channel. `0` while the channel is muted.                                                                                                                  |

## Delivery status and summaries

These parts and helpers are exported, to build a row that matches the default one:

| Name                                             | What it does                                                                                                                                                                                                                 |
| ------------------------------------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ChannelListItemTimestamp`                       | The time of `previewedMessage`, formatted like the default row.                                                                                                                                                              |
| `SummarizedMessagePreview`                       | The last-message line. Takes `latestMessage`, `messageDeliveryStatus` and `participantCount`. Shows the message text on one line without inline Markdown, as [The last-message line](#the-last-message-line) describes.      |
| `useLatestMessagePreview(params)`                | The data the last-message line is built from: `text`, `type`, `senderName` and `deliveryStatus`. Takes the same params. When the line shows the message text, `useLatestMessagePreview` returns it with its Markdown syntax. |
| `useChannelPreviewInfo({ channel })`             | `displayTitle`, `displayImage` and `groupChannelDisplayInfo`, reactively.                                                                                                                                                    |
| `useChannelDisplayName(channel)`                 | `displayTitle` alone.                                                                                                                                                                                                        |
| `getChannelDisplayImage(channel, currentUserId)` | `displayImage`, read once, not reactively.                                                                                                                                                                                   |
| `useChannelMembershipState(channel)`             | The user's membership, with `pinned_at` and `archived_at`.                                                                                                                                                                   |
| `useChannelListItemContext()`                    | `{ channel }`, for any component rendered inside a row. Throws outside one.                                                                                                                                                  |

### The last-message line

`<SummarizedMessagePreview/>` shows the message text on one line, without inline Markdown such as `**bold**` or links:

- List markers (`-`, `1.`, `[x]`, `[ ]`) and a table's `|` separators stay, so the shape of the message shows. A table's `---` row is dropped.
- The row's accessible name reads the words only: no bullets, checkboxes or `|`. Ordered-list numbers stay.
- A message that `isMessageAIGenerated` on `<Chat/>` marks as AI-generated keeps its text as it is.

For example, a message with the text `**Deploy** done:`, then the list items `- [x] ship` and `- [ ] docs`, shows "Deploy done: - [x] ship - [ ] docs", and the row's name reads "Deploy done: ship docs".

When the line shows the message text, `useLatestMessagePreview` returns it with its Markdown syntax. A row of your own that shows its `text` shows that syntax too. To show the line the default row shows, render `<SummarizedMessagePreview/>`.

`useLatestMessagePreview` returns a `type` for the kind of message, such as `text`, `image`, `giphy`, `voice`, `poll` or `deleted`. A `/giphy` message has the `giphy` type, not `image`. Its `deliveryStatus` adds `sending` to the three values of `MessageDeliveryStatus`.

## Hooks

- [`useChannelPreviewInfo`](https://getstream.io/chat/docs/sdk/react/reference/hooks/channel-and-thread-hooks/#usechannelpreviewinfo) and [`useChannelDisplayName`](https://getstream.io/chat/docs/sdk/react/reference/hooks/channel-and-thread-hooks/#usechanneldisplayname)
- [`useChannelMembershipState`](https://getstream.io/chat/docs/sdk/react/reference/hooks/channel-and-thread-hooks/#usechannelmembershipstate)

---

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