---
id: message_list
title: MessageList
---

import GHComponentLink from '../../_docusaurus-components/GHComponentLink';

import MessageActionsBoxWithCustomAction from '../../assets/message-actions-box-custom-actions.png';

The `MessageList` component renders a scrollable list of messages. The UI for each individual message is rendered
conditionally based on its `message.type` value. The list renders date separators, message reactions, new message notifications, system
messages, deleted messages, and standard messages containing text and/or attachments.

By default, the `MessageList` loads the most recent 25 messages held in the `channel.state`. More messages are fetched
from the Stream Chat API and loaded into the DOM on scrolling up the list. The currently loaded messages are held in
the `ChannelStateContext` and can be referenced with our custom hook.

```tsx
const { messages } = useChannelStateContext();
```

The `MessageList` has no required props and by default pulls overridable data from the various contexts established
in the [`Channel`](./channel.mdx) component. Customization of the messages rendered within the list is handled by
the [Message UI](../message-components/message-ui.mdx) component.

## Basic Usage

As a context consumer, the `MessageList` component must be rendered as a child of the `Channel` component. It can be
rendered with or without a provided `messages` prop. Providing your own `messages` value will override the default
value drawn from the `ChannelStateContext`.

**Example 1** - without `messages` prop

```tsx
<Chat client={client}>
  <ChannelList />
  <Channel>
    <MessageList />
    <MessageInput />
  </Channel>
</Chat>
```

**Example 2** - with `messages` prop

```tsx
const customMessages = [
  // array of messages
];

<Chat client={client}>
  <ChannelList />
  <Channel>
    <MessageList messages={customMessages} />
    <MessageInput />
  </Channel>
</Chat>;
```

## Message grouping

The `MessageList` internally creates a mapping of message id to a style group. There are 4 style groups - ` 'middle' | 'top' | 'bottom' | 'single'`. Later these group style tags are incorporated into the class of the `<li/>` element that wraps the `Message` component. This allows us to style messages by their position in the message group. An example of such class is `str-chat__li str-chat__li--bottom`.

## Custom message list rendering

You can completely change the way the message list is rendered by providing a custom `renderMessages` function. This function takes all the messages fetched so far (along with some additional data) and returns an array of React elements to render. By overriding the default behavior, you can add custom elements to the message list, change the way messages are grouped, add custom separators between messages, etc.

If you provide a custom `renderMessages` function, it's your responsibility to render each message type correctly. You can use the <GHComponentLink text='default implementation' path='/MessageList/renderMessages.tsx'/> as a reference. Or, if you just want to tweak a few things here and there, you can call `defaultRenderMessages` from your custom `renderMessages` function and build from there.

In this example, we use the default implementation for rendering a message list, and we add a custom element at the bottom of the list:

```tsx
const customRenderMessages: MessageRenderer<StreamChatGenerics> = (options) => {
  const elements = defaultRenderMessages(options);

  elements.push(<li key='caught-up'>You're all caught up!</li>);

  return elements;
};

const CustomMessageList = () => <MessageList renderMessages={customRenderMessages} />;
```

Make sure that the elements you return have `key`, as they will be rendered as an array. It's also a good idea to wrap each element with `<li>` to keep your markup semantically correct.

:::note
`MessageList` will re-render every time `renderMessages` function changes. For best performance, make sure that you don't recreate `renderMessages` function on every render: either move it to the global or module scope, or wrap it with `useCallback`.
:::

Custom message list rendering is only supported in `MessageList` and is currently not supported in `VirtualizedMessageList`.

## Props

### additionalMessageInputProps

Additional props to be passed to the `MessageInput` component, [available props](../message-input-components/message-input.mdx/#props). It is rendered when editing a message.

| Type   |
| ------ |
| object |

### closeReactionSelectorOnClick

If true, picking a reaction from the `ReactionSelector` component will close the selector.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### customMessageActions

An object containing custom message actions (key) and function handlers (value). For each custom action a dedicated item (button) in [`MessageActionsBox`](../message-components/message_ui#message-actions-box) is rendered. The key is used as a display text inside the button. Therefore, it should not be cryptic but rather bear the end user in mind when formulating it.

```jsx
const customActions = {
  'Copy text': (message) => {
    navigator.clipboard.writeText(message.text || '');
  },
};

<MessageList customMessageActions={customActions} />;
```

Custom action item "Copy text" in the message actions box:

<img
  src={MessageActionsBoxWithCustomAction}
  alt='Image of a custom action item "Copy text" in the message actions box'
  height='300'
/>

| Type   |
| ------ |
| object |

### disableDateSeparator

If true, disables the injection of date separator UI components in the `Channel` `MessageList` component.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### disableQuotedMessages

If true, disables the ability for users to quote messages.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### formatDate

Overrides the default date formatting logic, has access to the original date object.

| Type                   |
| ---------------------- |
| (date: Date) => string |

### getDeleteMessageErrorNotification

Function that returns the notification text to be displayed when the delete message request fails. This function receives the
deleted [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument.

| Type                               |
| ---------------------------------- |
| (message: StreamMessage) => string |

### getFetchReactionsErrorNotification

Function that returns the notification text to be displayed when loading message reactions fails. This function receives the
current [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument.

| Type                               |
| ---------------------------------- |
| (message: StreamMessage) => string |

### getFlagMessageErrorNotification

Function that returns the notification text to be displayed when a flag message request fails. This function receives the
flagged [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument.

| Type                               |
| ---------------------------------- |
| (message: StreamMessage) => string |

### getFlagMessageSuccessNotification

Function that returns the notification text to be displayed when a flag message request succeeds. This function receives the
flagged [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument.

| Type                               |
| ---------------------------------- |
| (message: StreamMessage) => string |

### getMarkMessageUnreadErrorNotification

Function that returns the notification text to be displayed when a mark message unread request fails. This function receives the
marked [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument.

| Type                               |
| ---------------------------------- |
| (message: StreamMessage) => string |

### getMarkMessageUnreadSuccessNotification

Function that returns the notification text to be displayed when a mark message unread request succeeds. This function receives the
marked [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument.

| Type                               |
| ---------------------------------- |
| (message: StreamMessage) => string |

### getMuteUserErrorNotification

Function that returns the notification text to be displayed when a mute user request fails. This function receives the
muted [user object](https://getstream.io/chat/docs/javascript/update_users/?language=javascript) as its argument.

| Type                           |
| ------------------------------ |
| (user: UserResponse) => string |

### getMuteUserSuccessNotification

Function that returns the notification text to be displayed when a mute user request succeeds. This function receives the
muted [user object](https://getstream.io/chat/docs/javascript/update_users/?language=javascript) as its argument.

| Type                           |
| ------------------------------ |
| (user: UserResponse) => string |

### getPinMessageErrorNotification

Function that returns the notification text to be displayed when a pin message request fails. This function receives the
pinned [message object](https://getstream.io/chat/docs/javascript/message_format/?language=javascript) as its argument.

| Type                               |
| ---------------------------------- |
| (message: StreamMessage) => string |

### groupStyles

Callback function to map each message in the list to a group style (` 'middle' | 'top' | 'bottom' | 'single'`).

| Type                                                                                                                       |
| -------------------------------------------------------------------------------------------------------------------------- |
| (message: StreamMessage, previousMessage: StreamMessage, nextMessage: StreamMessage, noGroupByUser: boolean) => GroupStyle |

### hasMore

Whether the list has more items to load.

| Type    | Default                                                                              |
| ------- | ------------------------------------------------------------------------------------ |
| boolean | [ChannelStateContextValue['hasMore']](../contexts/channel-state-context.mdx#hasmore) |

### headerPosition

Position to render the `HeaderComponent` in the list.

| Type   |
| ------ |
| number |

### hideDeletedMessages

If true, removes the `MessageDeleted` components from the list.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### hideNewMessageSeparator

If true, hides the `DateSeparator` component that renders when new messages are received in a channel that's watched but not active.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### internalInfiniteScrollProps

Additional props for the underlying <GHComponentLink text='InfiniteScroll' path='/InfiniteScrollPaginator/InfiniteScroll.tsx'/> component.

| Type   |
| ------ |
| object |

### loadingMore

Whether the list is currently loading more items.

| Type    | Default                                                                                      |
| ------- | -------------------------------------------------------------------------------------------- |
| boolean | [ChannelStateContextValue['loadingMore']](../contexts/channel-state-context.mdx#loadingmore) |

### loadMore

Function called when more messages are to be loaded, provide your own function to override the handler stored in context.

| Type     | Default                                                                                  |
| -------- | ---------------------------------------------------------------------------------------- |
| function | [ChannelActionContextValue['loadMore']](../contexts/channel-action-context.mdx#loadmore) |

### Message

Custom UI component to display an individual message.

| Type      | Default                                                                   |
| --------- | ------------------------------------------------------------------------- |
| component | <GHComponentLink text='MessageSimple' path='/Message/MessageSimple.tsx'/> |

### messageActions

Array of allowed message actions (ex: 'edit', 'delete', 'reply'). To disable all actions, provide an empty array.

| Type  | Default                                                              |
| ----- | -------------------------------------------------------------------- |
| array | ['edit', 'delete', 'flag', 'mute', 'pin', 'quote', 'react', 'reply'] |

### messageLimit

The limit to use when paginating new messages (the page size).

:::caution
After mounting, the `MessageList` component checks if the list is completely filled with messages. If there is some space left in the list, `MessageList` will load the next page of messages, but it will do so _only once_. This means that if your `messageLimit` is too low, or if your viewport is very large, the list will not be completely filled. Set the limit with this in mind.
:::

| Type   | Default |
| ------ | ------- |
| number | 100     |

### messages

The messages to render in the list. Provide your own array to override the data stored in context.

| Type  | Default                                                                                |
| ----- | -------------------------------------------------------------------------------------- |
| array | [ChannelStateContextValue['messages']](../contexts/channel-state-context.mdx#messages) |

### noGroupByUser

If true, turns off message UI grouping by user.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### onlySenderCanEdit

If true, only the sender of the message has editing privileges. If `false` also channel capability `update-any-message` has to be enabled in order a user can edit other users' messages.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### onMentionsClick

Custom action handler function to run on click on a @mention in a message.

| Type     | Default                                                                                                |
| -------- | ------------------------------------------------------------------------------------------------------ |
| function | [ChannelActionContextValue['onMentionsClick']](../contexts/channel-action-context.mdx#onmentionsclick) |

### onMentionsHover

Custom action handler function to run on hover over a @mention in a message.

| Type     | Default                                                                                                |
| -------- | ------------------------------------------------------------------------------------------------------ |
| function | [ChannelActionContextValue['onMentionsHover']](../contexts/channel-action-context.mdx#onmentionshover) |

### onUserClick

Custom action handler function to run on click of user avatar.

| Type                                                  |
| ----------------------------------------------------- |
| (event: React.BaseSyntheticEvent, user: User) => void |

### onUserHover

Custom action handler function to run on hover of user avatar.

| Type                                                  |
| ----------------------------------------------------- |
| (event: React.BaseSyntheticEvent, user: User) => void |

### openThread

Custom action handler to open a [`Thread`](./thread.mdx) component.

| Type     | Default                                                                                      |
| -------- | -------------------------------------------------------------------------------------------- |
| function | [ChannelActionContextValue['openThread']](../contexts/channel-action-context.mdx#openthread) |

### pinPermissions

The user roles allowed to pin messages in various channel types (deprecated in favor of `channelCapabilities`).

| Type   | Default                                                                   |
| ------ | ------------------------------------------------------------------------- |
| object | <GHComponentLink text='defaultPinPermissions' path='/Message/utils.tsx'/> |

### renderText {#render-text}

Custom function to render message text content.

| Type     | Default                                                                        |
| -------- | ------------------------------------------------------------------------------ |
| function | <GHComponentLink text='renderText' path='/Message/renderText/renderText.tsx'/> |

### renderMessages

Custom function to render message text content.

| Type     | Default                                                                                |
| -------- | -------------------------------------------------------------------------------------- |
| function | <GHComponentLink text='defaultRenderMessages' path='/MessageList/renderMessages.tsx'/> |

#### Parameters

The function receives a single object with the following properties:

| Name                  | Type                                                                                          | Description                                                                                                                                        |
| --------------------- | --------------------------------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------- |
| components            | [ComponentContextValue](../contexts/component-context.mdx)                                    | UI components, including possible overrides                                                                                                        |
| customClasses         | object                                                                                        | Object containing [custom CSS classnames](../../components/core-components/chat.mdx#customclasses) to override the library's default container CSS |
| lastReceivedMessageId | string                                                                                        | The latest message ID in the current channel                                                                                                       |
| messageGroupStyles    | string[]                                                                                      | An array of potential styles to apply to a grouped message (ex: top, bottom, single)                                                               |
| messages              | Array<[ChannelStateContextValue['messages']](../contexts/channel-state-context.mdx#messages)> | The messages to render in the list                                                                                                                 |
| readData              | object                                                                                        | The read state for for messages submitted by the user themselves                                                                                   |
| sharedMessageProps    | object                                                                                        | Object containing props that can be directly passed to the `Message` component                                                                     |

#### Return value

The function is expected to return an array of valid React nodes: `Array<ReactNode>`. For best performance, each node should have a `key`.

### retrySendMessage

Custom action handler to retry sending a message after a failed request.

| Type     | Default                                                                                                  |
| -------- | -------------------------------------------------------------------------------------------------------- |
| function | [ChannelActionContextValue['retrySendMessage']](../contexts/channel-action-context.mdx#retrysendmessage) |

### returnAllReadData

If true, `readBy` data supplied to the `Message` components will include all user read states per sent message. By default,
only `readBy` data for a user's most recently sent message is returned.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### reviewProcessedMessage

Allows to review changes introduced to messages array on per message basis (for example date separator injection before a message). The array returned from the function is appended to the array of messages that are later rendered into React elements in the `MessageList`.

The function expects a single parameter, which is an object containing the following attributes:

- `changes` - array of messages representing the changes applied around a given processed message
- `context` - configuration params and information forwarded from `processMessages`
- `index` - index of the processed message in the original messages array
- `messages` - array of messages retrieved from the back-end
- `processedMessages` - newly built array of messages to be later rendered

The `context` has the following parameters:

- `userId` - the connected user ID;
- `enableDateSeparator` - flag determining whether the date separators will be injected Enable date separator
- `hideDeletedMessages` - flag determining whether deleted messages would be filtered out during the processing
- `hideNewMessageSeparator` - disables date separator display for unread incoming messages
- `lastRead`: Date when the channel has been last read. Sets the threshold after everything is considered unread

The example below demonstrates how the custom logic can decide, whether deleted messages should be rendered on a given date. In this example, the deleted messages neither the date separator would be rendered if all the messages on a given date are deleted.

```js
const getMsgDate = (msg) =>
  (msg && msg.created_at && isDate(msg.created_at) && msg.created_at.toDateString()) || '';

const dateSeparatorFilter = (msg) => msg.customType !== 'message.date';

const msgIsDeleted = (msg) => msg.type === 'deleted';

const reviewProcessedMessage = ({ changes, context, index, messages, processedMessages }) => {
  if (!context.enableDateSeparator) return changes;

  const changesWithoutSeparator = changes.filter(dateSeparatorFilter);
  const dateSeparatorInjected = changesWithoutSeparator.length !== changes.length;
  const previousProcessedMessage = processedMessages[processedMessages.length - 1];
  const processedMessage = messages[index];
  const processedMessageDate = getMsgDate(processedMessage);

  if (dateSeparatorInjected) {
    if (!processedMessageDate) return changes;
    const followingMessages = messages.slice(index + 1);
    let allFollowingMessagesOnDateDeleted = false;

    for (const followingMsg of followingMessages) {
      const followingMsgDate = getMsgDate(followingMsg);
      if (followingMsgDate !== processedMessageDate) break;
      allFollowingMessagesOnDateDeleted = followingMsg.type === 'deleted';
    }

    return allFollowingMessagesOnDateDeleted ? [] : changes;
  } else if (
    msgIsDeleted(processedMessage) &&
    getMsgDate(previousProcessedMessage) !== getMsgDate(processedMessage)
  ) {
    return [];
  } else {
    return changes;
  }
};
```

### scrolledUpThreshold

The pixel threshold to determine whether the user is scrolled up in the list. When scrolled up in the active
channel, the `MessageNotification` component displays when new messages arrive.

| Type   | Default |
| ------ | ------- |
| number | 200     |

### showUnreadNotificationAlways

The floating notification informing about unread messages will be shown when the `UnreadMessagesSeparator` is not visible. The default is false, that means the notification
is shown only when viewing unread messages.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### sortReactionDetails

Comparator function to sort the list of reacted users. Should have the same signature as an array's `sort` method.

| Type                                                       | Default            |
| ---------------------------------------------------------- | ------------------ |
| (this: ReactionResponse, that: ReactionResponse) => number | alphabetical order |

### sortReactions

Comparator function to sort reactions. Should have the same signature as the `sort` method for a string array.

| Type                                                     | Default            |
| -------------------------------------------------------- | ------------------ |
| (this: ReactionSummary, that: ReactionSummary) => number | alphabetical order |

### threadList

If true, indicates that the current `MessageList` component is part of a `Thread`.

| Type    | Default |
| ------- | ------- |
| boolean | false   |

### unsafeHTML

If true, renders HTML instead of markdown. Posting HTML is only supported server-side.

| Type    | Default |
| ------- | ------- |
| boolean | false   |
