# MessageList

`MessageList` renders a scrollable list of messages. Each item’s UI is chosen based on `message.type`. It can render date separators, reactions, new-message notifications, system messages, deleted messages, and standard text/attachment messages.

By default, `MessageList` loads the most recent 25 messages from `channel.state`. Older messages are fetched as you scroll up. The loaded messages live in `ChannelStateContext` and can be accessed via:

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

`MessageList` has no required props and reads data from the `Channel` contexts provided by [`Channel`](/chat/docs/sdk/react/v13/components/core-components/channel/). Customize message rendering via the [Message UI component](/chat/docs/sdk/react/v13/components/message-components/message_ui/).

## Best Practices

- Keep `MessageList` under `Channel` so it can access state and actions.
- Avoid passing `messages` unless you need to fully control list contents.
- Use `renderMessages` only for structural changes; keep it stable via `useCallback`.
- Preserve list semantics (`<li>` per message) to keep layout and a11y intact.
- Prefer the default renderer as a baseline when adding custom separators.

## Basic Usage

`MessageList` must be rendered under `Channel`. You can optionally pass a `messages` prop to override the default `ChannelStateContext` messages.

**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

`MessageList` groups messages by position (`'middle' | 'top' | 'bottom' | 'single'`) and adds a class to each `<li>` (for example, `str-chat__li str-chat__li--bottom`) so you can style grouped messages.

## Custom message list rendering

You can replace the entire rendering pipeline by providing `renderMessages`. It receives the loaded messages (and extra metadata) and returns React elements, so you can add custom separators, grouping, or additional items.

If you provide a custom `renderMessages`, you’re responsible for handling all message types. Use the [default implementation](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageList/renderMessages.tsx) as a baseline, or call `defaultRenderMessages` and build on top.

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 = (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 returned elements have `key` values. It’s also best to wrap each element in `<li>` to keep list markup valid.

<admonition type="note">

`MessageList` re-renders whenever `renderMessages` changes. For best performance, avoid recreating it on every render; move it to module scope or wrap with `useCallback`.

</admonition>

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](/chat/docs/sdk/react/v13/components/message-input-components/message_input/#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`](/chat/docs/sdk/react/v13/components/message-components/message_ui/) 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.

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

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

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

![Image of a custom action item ](@chat-sdk/react/v13/_assets/message-actions-box-custom-actions.png)

| 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](/chat/docs/javascript/send_message/) as its argument.

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

### getFetchReactionsErrorNotification

Function that returns the notification text to be displayed when loading message reactions fails. This function receives the
current [message object](/chat/docs/javascript/send_message/) as its argument.

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

### getFlagMessageErrorNotification

Function that returns the notification text to be displayed when a flag message request fails. This function receives the
flagged [message object](/chat/docs/javascript/send_message/) as its argument.

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

### getFlagMessageSuccessNotification

Function that returns the notification text to be displayed when a flag message request succeeds. This function receives the
flagged [message object](/chat/docs/javascript/send_message/) as its argument.

| Type                              |
| --------------------------------- |
| (message: LocalMessage) => 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](/chat/docs/javascript/send_message/) as its argument.

| Type                              |
| --------------------------------- |
| (message: LocalMessage) => 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](/chat/docs/javascript/send_message/) as its argument.

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

### getMuteUserErrorNotification

Function that returns the notification text to be displayed when a mute user request fails. This function receives the
muted [user object](/chat/docs/javascript/update_users/) 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](/chat/docs/javascript/update_users/) 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](/chat/docs/javascript/send_message/) as its argument.

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

### groupStyles

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

| Type                                                                                                                                                                     |
| ------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| (message: RenderedMessage, previousMessage: RenderedMessage, nextMessage: RenderedMessage, noGroupByUser: boolean, maxTimeBetweenGroupedMessages?: number) => GroupStyle |

### hasMore

Whether the list has more items to load.

| Type    | Default                                                                                                           |
| ------- | ----------------------------------------------------------------------------------------------------------------- |
| boolean | [ChannelStateContextValue['hasMore']](/chat/docs/sdk/react/v13/components/contexts/channel_state_context#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 [InfiniteScroll](https://github.com/GetStream/stream-chat-react/blob/master/src/components/InfiniteScrollPaginator/InfiniteScroll.tsx) component.

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

### loadingMore

Whether the list is currently loading more items.

| Type    | Default                                                                                                                   |
| ------- | ------------------------------------------------------------------------------------------------------------------------- |
| boolean | [ChannelStateContextValue['loadingMore']](/chat/docs/sdk/react/v13/components/contexts/channel_state_context#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']](/chat/docs/sdk/react/v13/components/contexts/channel_action_context#loadmore) |

### maxTimeBetweenGroupedMessages

Maximum time in milliseconds that should occur between messages to still consider them grouped together.

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

### Message

Custom UI component to display an individual message.

| Type      | Default                                                                                                              |
| --------- | -------------------------------------------------------------------------------------------------------------------- |
| component | [MessageSimple](https://github.com/GetStream/stream-chat-react/blob/master/src/components/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', 'markUnread', 'mute', 'pin', 'quote', 'react', 'remindMe', 'reply', 'saveForLater'] |

It is also possible to display actions that are by default supported by the SDK, but not active by default:

```tsx
import {
  MessageList,
  MESSAGE_ACTIONS,
  OPTIONAL_MESSAGE_ACTIONS,
} from "stream-chat-react";

const messageActions = [
  ...Object.keys(MESSAGE_ACTIONS),
  OPTIONAL_MESSAGE_ACTIONS.deleteForMe, // has to be explicitly added to the messageActions array
];

<MessageList messageActions={messageActions} />;
```

### messageLimit

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

<admonition type="warning">

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.

</admonition>

| 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']](/chat/docs/sdk/react/v13/components/contexts/channel_state_context#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']](/chat/docs/sdk/react/v13/components/contexts/channel_action_context#onmentionsclick) |

### onMentionsHover

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

| Type     | Default                                                                                                                             |
| -------- | ----------------------------------------------------------------------------------------------------------------------------------- |
| function | [ChannelActionContextValue['onMentionsHover']](/chat/docs/sdk/react/v13/components/contexts/channel_action_context#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 handler invoked when the button in the `Message` component that opens [`Thread`](/chat/docs/sdk/react/v13/components/core-components/thread/) component is clicked. To be able to define custom logic to `openThread`, we need to have a wrapper around `MessageList` component and reach out to `ChannelActionContext` for the default `openThread` function.

```tsx
import { useCallback } from "react";
import { MessageList, useChannelActionContext } from "stream-chat-react";
import type { LocalMessage } from "stream-chat";

const MessageListWrapper = () => {
  const { openThread: contextOpenThread } = useChannelActionContext();

  const openThread = useCallback(
    (message: LocalMessage, event?: React.BaseSyntheticEvent) => {
      // custom logic
      contextOpenThread(message, event);
    },
    [contextOpenThread],
  );

  return <MessageList openThread={openThread} />;
};
```

| Type                                                                | Default                                                                                                                   |
| ------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------- |
| `(message: LocalMessage, event?: React.BaseSyntheticEvent) => void` | [ChannelActionContextValue['openThread']](/chat/docs/sdk/react/v13/components/contexts/channel_action_context#openthread) |

### pinPermissions

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

| Type   | Default                                                                                                              |
| ------ | -------------------------------------------------------------------------------------------------------------------- |
| object | [defaultPinPermissions](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/utils.tsx) |

### renderText

Custom function to render message text content.

| Type     | Default                                                                                                                   |
| -------- | ------------------------------------------------------------------------------------------------------------------------- |
| function | [renderText](https://github.com/GetStream/stream-chat-react/blob/master/src/components/Message/renderText/renderText.tsx) |

### renderMessages

Custom function to render message text content.

| Type     | Default                                                                                                                           |
| -------- | --------------------------------------------------------------------------------------------------------------------------------- |
| function | [defaultRenderMessages](https://github.com/GetStream/stream-chat-react/blob/master/src/components/MessageList/renderMessages.tsx) |

#### Parameters

The function receives a single object with the following properties:

| Name                  | Type                                                                                                                             | Description                                                                                                                                                        |
| --------------------- | -------------------------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| components            | [ComponentContextValue](/chat/docs/sdk/react/v13/components/contexts/component_context/)                                         | UI components, including possible overrides                                                                                                                        |
| customClasses         | object                                                                                                                           | Object containing [custom CSS classnames](/chat/docs/sdk/react/v13/components/core-components/chat#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&lt;[ChannelStateContextValue['messages']](/chat/docs/sdk/react/v13/components/contexts/channel_state_context#messages)&gt; | 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']](/chat/docs/sdk/react/v13/components/contexts/channel_action_context#retrysendmessage) |

### returnAllReadData

If true, `readBy` and `deliveredTo` (as of the version 13.8.0) data supplied to the `Message` components will include all user read states per sent message. By default,
only `readBy` and `deliveredTo` (as of the version 13.8.0) 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   |

### reactionDetailsSort

Sort options to provide to a reactions query. Affects the order of reacted users in the default reactions modal.

| Type                     | Default                     |
| ------------------------ | --------------------------- |
| `{ created_at: number }` | reverse chronological 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 | chronological 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   |


---

This page was last updated at 2026-04-21T07:55:45.032Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react/v13/components/core-components/message_list/](https://getstream.io/chat/docs/sdk/react/v13/components/core-components/message_list/).