# MessageList

> **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/).

`MessageList` renders the loaded messages of the channel or the thread it sits in, in an inverted `FlatList`, and turns the user's scrolling into paginator calls. Inside a `Thread` it renders `thread.messagePaginator`, with the parent message above the replies; otherwise `channel.messagePaginator`. [Message list UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/) explains what it shows, and how it differs from [`MessageFlashList`](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message-list/messageflashlist/).

## Best practices

- Render it inside a `Channel` or a `Thread`. It reads the paginator, the composer's height and the message settings from the contexts they provide, so the same `<MessageList />` works in both.
- Pass `onThreadSelect` in a channel. The replies button and the thread reply action call it with the message's `Thread`, and do nothing without it.
- Change how one message looks with the `MessageItemView` override, and the actions with `messageActions` on `Channel`. See [Message actions](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/actions/#message-actions). The list has no prop for either.
- Declare the components you pass, such as `FooterComponent` and `HeaderComponent`, outside the component that renders the list, and keep `additionalFlatListProps` stable.
- Use `setFlatListRef` to reach the `FlatList`, not a `ref` in `additionalFlatListProps`.

## Basic usage

```tsx title="src/ChannelScreen.tsx"
import type { Channel as StreamChannel, Thread } from "stream-chat";
import {
  Channel,
  MessageComposer,
  MessageList,
} from "stream-chat-react-native";

type ChannelScreenProps = {
  channel: StreamChannel;
  onOpenThread: (thread: Thread) => void;
};

export const ChannelScreen = ({
  channel,
  onOpenThread,
}: ChannelScreenProps) => (
  <Channel channel={channel}>
    <MessageList onThreadSelect={onOpenThread} />
    <MessageComposer />
  </Channel>
);
```

In a thread, render it inside `<Thread thread={thread}>` the same way, without `onThreadSelect`. How a component of yours reads the paginator the list renders is on [Reading state in components](https://getstream.io/chat/docs/sdk/react-native/v10/ui/reading-state-in-components/#which-owner-a-hook-reads).

## Message grouping

The list groups consecutive messages from the same user. Each message gets a group style, `top`, `middle`, `bottom` or `single`, which decides its padding, its bubble corners, and whether the avatar and the footer with the time show: only the last message of a group, `bottom` or `single`, shows them, and a message that is still sending or failed keeps its footer.

- `enableMessageGroupingByUser={false}` on `Channel`, or `noGroupByUser` on the list, turns grouping off. Every message then gets an empty group style, so no message counts as the last of its group: no message shows the avatar, and only a message that is sending or failed shows the footer with the time.
- `maxTimeBetweenGroupedMessages` on `Channel` starts a new group when two messages are further apart than this many milliseconds.
- `getMessageGroupStyle` on `Channel` replaces the rule. It receives the message, its neighbors and the date separators around it, and returns the group styles. The default is the exported `getGroupStyle`.

## What the list renders

Around the messages, the list renders:

| Part                                                                          | When                                                                             | Override key                     |
| ----------------------------------------------------------------------------- | -------------------------------------------------------------------------------- | -------------------------------- |
| The older-end indicator, under the parent message in a thread                 | the indicator while an older page loads, the parent message always               | none, the `FooterComponent` prop |
| The newer-end indicator and the typing indicator                              | while a newer page loads, and while someone types                                | none, the `HeaderComponent` prop |
| `StickyHeader`                                                                | while the list has messages, unless `hideStickyDateHeader` is set                | `StickyHeader`                   |
| `ScrollToBottomButton`                                                        | while the list isn't at the latest message, or the latest messages aren't loaded | `ScrollToBottomButton`           |
| `UnreadMessagesNotification`                                                  | in a channel, while the last read message is above the screen                    | `UnreadMessagesNotification`     |
| `NetworkDownIndicator`                                                        | while the device is offline or the connection is down                            | `NetworkDownIndicator`           |
| The composer's suggestion list                                                | while the composer shows suggestions                                             | `AutoCompleteSuggestionList`     |
| The `NotificationList` of the channel or thread                               | while it has notifications                                                       | `NotificationList`               |
| `EmptyStateIndicator` with `listType="message"`, in place of the list         | in a channel with no messages                                                    | `EmptyStateIndicator`            |
| `MessageListLoadingIndicator` with `listType="message"`, in place of the list | while the first page loads                                                       | `MessageListLoadingIndicator`    |

For each message the list renders the date separator when a day starts, the `Message` override, and the unread separator under the last read message. A system message renders `MessageSystem` instead. [Floating controls](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/#floating-controls) explains when each control shows, and [Separators](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/#separators) the separators.

## Props

`MessageListProps` makes every prop optional. The props marked "from" a context default to that context's value, so you set them only to override it.

| Prop                      | Type                                                                 | Default                                                                     | Description                                                                                                                                                                                                                                                                                                                                                                        |
| ------------------------- | -------------------------------------------------------------------- | --------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `additionalFlatListProps` | `Partial<FlatListProps<MessageListItemWithNeighbours>>`              |                                                                             | Props for the inner `FlatList`. `style` and `contentContainerStyle` are merged with the list's own, and `accessibilityActions` and `onAccessibilityAction` are combined with the list's scroll-to-bottom action. Any other key replaces the list's prop of the same name, `onLayout` and `onContentSizeChange` included. Each item is `{ message, previousMessage, nextMessage }`. |
| `animateLayout`           | `boolean`                                                            | `true`                                                                      | Animates layout changes with a Reanimated layout transition. With `false`, the list renders the `FlatList` from `MessagesContext` instead.                                                                                                                                                                                                                                         |
| `attachmentPickerStore`   | `AttachmentPickerStore`                                              | from `AttachmentPickerContext`                                              | The attachment picker's state. A touch on the list closes the picker.                                                                                                                                                                                                                                                                                                              |
| `channel`                 | `Channel`                                                            | from `ChannelContext`                                                       | The channel whose messages the list renders.                                                                                                                                                                                                                                                                                                                                       |
| `client`                  | `StreamChat`                                                         | from `ChatContext`                                                          | The client.                                                                                                                                                                                                                                                                                                                                                                        |
| `closePicker`             | `() => void`                                                         | from `AttachmentPickerContext`                                              | Closes the attachment picker.                                                                                                                                                                                                                                                                                                                                                      |
| `disabled`                | `boolean`                                                            | from `ChannelContext`                                                       | `true` while the channel is frozen. When it turns `true`, the scroll-to-bottom button hides.                                                                                                                                                                                                                                                                                       |
| `disableTypingIndicator`  | `boolean`                                                            | from `MessagesContext`                                                      | Leaves the typing indicator out of the default `HeaderComponent`.                                                                                                                                                                                                                                                                                                                  |
| `FlatList`                | `typeof FlatList`                                                    | from `MessagesContext`                                                      | The list component the list renders when `animateLayout` is `false`. React Native's `FlatList` unless `Channel` sets another.                                                                                                                                                                                                                                                      |
| `FooterComponent`         | `React.ComponentType<{ loadingMore?: boolean }>`                     | `ThreadFooterComponent` in a thread, `InlineLoadingMoreIndicator` otherwise | Rendered at the older end, the top of the screen, and receives `loadingMore`. In a thread the default renders the parent message, so a replacement replaces it too.                                                                                                                                                                                                                |
| `HeaderComponent`         | `React.ComponentType`                                                | the newer-end loading indicator, then the typing indicator                  | Rendered at the newer end, the bottom of the screen. It receives no props, and a replacement removes the typing indicator unless it renders one.                                                                                                                                                                                                                                   |
| `hideStickyDateHeader`    | `boolean`                                                            | from `ChannelContext`                                                       | Turns off the sticky date header.                                                                                                                                                                                                                                                                                                                                                  |
| `inverted`                | `boolean`                                                            | `true`                                                                      | Sets `inverted` on the `FlatList`. The list's paging and scroll handling assume an inverted list.                                                                                                                                                                                                                                                                                  |
| `isLiveStreaming`         | `boolean`                                                            | `false`                                                                     | Tunes the list for many messages a second: list updates are batched to one per frame, the list keeps following new messages from up to 300 points away instead of 10, scroll events arrive every 16 ms, and `FlatList`'s `strictMode` is on from React Native 0.87. Experimental.                                                                                                  |
| `markRead`                | `(options?: MarkReadFunctionOptions) => void`                        | `useMarkRead(channel)`                                                      | Marks the channel read. In a channel, the list calls it when a new message arrives while the user views the latest messages, and, with `updateChannelUnreadState: false`, when the user taps the scroll-to-bottom button. The unread notification calls it when closed.                                                                                                            |
| `messageInputFloating`    | `boolean`                                                            | from `MessageInputContext`                                                  | With `true`, the list pads its content by the composer's height and lifts its floating parts above the composer.                                                                                                                                                                                                                                                                   |
| `messageInputHeightStore` | `MessageInputHeightStore`                                            | from `MessageInputContext`                                                  | The store holding the composer's height.                                                                                                                                                                                                                                                                                                                                           |
| `myMessageTheme`          | `DeepPartial<Theme>`                                                 | from `MessagesContext`                                                      | A theme merged over the current one for the user's own messages.                                                                                                                                                                                                                                                                                                                   |
| `noGroupByUser`           | `boolean`                                                            | `true` when `Channel` has `enableMessageGroupingByUser={false}`             | Turns grouping off. The list combines it with the `Channel` setting, so `false` doesn't turn grouping on when `Channel` turned it off.                                                                                                                                                                                                                                             |
| `onListScroll`            | `ScrollViewProps['onScroll']`                                        |                                                                             | Called with every scroll event.                                                                                                                                                                                                                                                                                                                                                    |
| `onThreadSelect`          | `(thread: Thread) => void`                                           |                                                                             | Called with the message's `Thread` when the user presses a message's replies button or picks the thread reply action. Render it in a `<Thread thread={thread}>`.                                                                                                                                                                                                                   |
| `pendingUploadsEnabled`   | `boolean`                                                            | `messageComposer.attachments.pendingUploadsEnabled`                         | With `true`, the list's `NotificationList` leaves out the notifications of canceled uploads.                                                                                                                                                                                                                                                                                       |
| `readEvents`              | `boolean`                                                            | from `OwnCapabilitiesContext`                                               | Whether the user can send read events. Without them the unread notification shows only when the channel counts unread messages locally.                                                                                                                                                                                                                                            |
| `setFlatListRef`          | `(ref: FlatListType<MessageListItemWithNeighbours> \| null) => void` |                                                                             | Receives the ref of the inner `FlatList`.                                                                                                                                                                                                                                                                                                                                          |
| `thread`                  | `Thread`                                                             | from `ThreadContext`                                                        | The thread whose replies the list renders.                                                                                                                                                                                                                                                                                                                                         |

`MessageListItemWithNeighbours`, `AttachmentPickerStore` and `MessageInputHeightStore` aren't exported, so type a callback that receives them through `MessageListProps`, for example `MessageListProps['setFlatListRef']`.

## Parts the list renders

These are the defaults of the override keys above. Replace one with `WithComponents`; [Overriding components](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overriding-components/) explains how. `StickyHeader` and `UnreadMessagesNotification` aren't exported, so a replacement can't wrap them.

### InlineDateSeparator

Renders the date above the first message of a day. The text comes from the `timestamp.InlineDateSeparator` translation key, and screen readers get the full date.

| Prop   | Type   | Default | Description       |
| ------ | ------ | ------- | ----------------- |
| `date` | `Date` |         | The date to show. |

### InlineUnreadIndicator

Renders the unread separator under the last read message: "5 new messages", or "Unread Messages" without a count.

| Prop          | Type     | Default | Description                                                          |
| ------------- | -------- | ------- | -------------------------------------------------------------------- |
| `unreadCount` | `number` |         | The number of unread messages, from the paginator's unread snapshot. |

### StickyHeader and DateHeader

`StickyHeader` receives the date of the topmost message on screen, formats it with the `timestamp.StickyHeader` translation key, and renders the `DateHeader` override with the result. It renders nothing without a `date`.

| Prop         | Type               | Default | Description                                                                      |
| ------------ | ------------------ | ------- | -------------------------------------------------------------------------------- |
| `date`       | `Date`             |         | The date to show.                                                                |
| `dateString` | `string \| number` |         | Text shown in place of the formatted `date`. It's read only when `date` changes. |

`DateHeader` renders the label.

| Prop         | Type               | Default | Description       |
| ------------ | ------------------ | ------- | ----------------- |
| `dateString` | `string \| number` |         | The text to show. |

### UnreadMessagesNotification

Renders "5 unread", or "Unread Messages" without a count, with a close button. The count is the paginator's unread snapshot. The list passes `markRead` and an `onCloseHandler` that marks the channel read and hides the notification.

| Prop             | Type                                          | Default                           | Description                                                                                   |
| ---------------- | --------------------------------------------- | --------------------------------- | --------------------------------------------------------------------------------------------- |
| `markRead`       | `(options?: MarkReadFunctionOptions) => void` |                                   | Marks the channel read. Called by the close button when there's no `onCloseHandler`.          |
| `onCloseHandler` | `() => void`                                  | calls `markRead`                  | Called when the user presses the close button.                                                |
| `onPressHandler` | `() => Promise<void>`                         | jumps to the first unread message | Called when the user presses the notification. A failed jump publishes an error notification. |

### InlineLoadingMoreIndicator and InlineLoadingMoreRecentIndicator

The spinners the default `FooterComponent` and `HeaderComponent` render. They aren't override keys; pass your own `FooterComponent` or `HeaderComponent` instead.

| Prop          | Type      | Default | Description                                                  |
| ------------- | --------- | ------- | ------------------------------------------------------------ |
| `loadingMore` | `boolean` |         | `InlineLoadingMoreIndicator` renders a spinner while `true`. |

| Prop                | Type      | Default | Description                                                        |
| ------------------- | --------- | ------- | ------------------------------------------------------------------ |
| `loadingMoreRecent` | `boolean` |         | `InlineLoadingMoreRecentIndicator` renders a spinner while `true`. |

`NetworkDownIndicator` takes no props. It shows "Waiting for network..." while the device is offline and "Reconnecting..." while the connection to Stream is down.

## Related hooks

| Hook                                 | Returns                                                                                                                                                               |
| ------------------------------------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `useMessagePaginator()`              | the paginator the list renders: `thread.messagePaginator` inside a `Thread`, otherwise `channel.messagePaginator`                                                     |
| `useChannel()`, `useThreadContext()` | the channel and the thread whose paginator the list renders                                                                                                           |
| `useStateStore(store, selector)`     | a selection of the paginator's state, such as its `items`                                                                                                             |
| `useMessagesContext()`               | the message settings of `Channel` or `Thread`. See [MessagesContext](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message-list/messagescontext/)               |
| `useMessageContext()`                | the message and its handlers, inside each message the list renders. See [MessageContext](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/messagecontext/) |
| `useMarkRead(channel)`               | the `markRead` callback the list uses by default                                                                                                                      |
| `useTypingString()`                  | the "Cleo is typing" text of the list's channel or thread                                                                                                             |

The paginator's API is on [Message paginator](https://getstream.io/chat/docs/sdk/react-native/v10/reference/state/message-paginator/), and jumping to a message on [Message paginators](https://getstream.io/chat/docs/sdk/react-native/v10/state/loading-data/message-paginators/).

---

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