# Message UI

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

The message view is the component that draws one message. [`Message`](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/message/) renders the `MessageItemView` override with no props, and the view reads the message and its handlers from [`MessageContext`](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/messagecontext/). The default is `MessageItemView`, which lays out the avatar, the headers, the bubble, the reactions, the replies button and the footer, and renders the bubble's content with `MessageContent`. [A message](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/#a-message) explains how the parts fit together.

## Best practices

- Replace one part through its override key, and keep the rest of the default view. The keys are in [Override paths](#override-paths).
- Add to the bubble with the content slots before you replace `MessageContent` or `MessageItemView`. They render inside the bubble and need no props.
- A message view of your own handles the kinds of message your app has. The default covers deleted, failed and error messages, Giphy previews, polls, quoted messages and AI-generated text. Blocked messages render `MessageBlocked`, and system messages `MessageSystem`, instead of the view.
- Keep the long press menu in a view of your own: call `onLongPress` from the context, and attach `contextMenuAnchorRef` to the bubble.
- Declare the `overrides` object once, outside the component that renders `WithComponents`.

## Basic usage

`MessageItemView` also takes its context values as props, and a prop wins over the context. A wrapper registered as the override changes one value for every message. This one turns off swipe to reply on the messages of bots:

```tsx title="src/MessageItemViewWithoutBotSwipe.tsx"
import {
  MessageItemView,
  useMessageContext,
  WithComponents,
} from "stream-chat-react-native";

const MessageItemViewWithoutBotSwipe = () => {
  const { message } = useMessageContext();

  return (
    <MessageItemView
      enableSwipeToReply={!message.user?.id?.startsWith("bot-")}
    />
  );
};

const overrides = { MessageItemView: MessageItemViewWithoutBotSwipe };

export const MessagesWithoutBotSwipe = ({
  children,
}: {
  children: React.ReactNode;
}) => <WithComponents overrides={overrides}>{children}</WithComponents>;
```

## UI customization

A message view of your own composes the exported parts it needs. They read the same context, so most need no props. This one keeps the avatar, the bubble with its content, the reactions and the footer, and drops the headers, the replies button and swipe to reply:

```tsx title="src/PlainMessageItemView.tsx"
import { StyleSheet, View } from "react-native";
import { convertTimestampToDate } from "stream-chat";
import {
  MessageAuthor,
  MessageContent,
  MessageDeleted,
  MessageFooter,
  ReactionListBottom,
  useMessageContext,
  useTheme,
  WithComponents,
} from "stream-chat-react-native";

const PlainMessageItemView = () => {
  const { alignment, contextMenuAnchorRef, groupStyles, isMyMessage, message } =
    useMessageContext();
  const {
    theme: { semantics },
  } = useTheme();
  const date = convertTimestampToDate(message.created_at);

  if (message.type === "deleted") {
    return (
      <MessageDeleted
        date={date}
        groupStyle={`${alignment}_${groupStyles[0] ?? ""}`}
      />
    );
  }

  return (
    <View style={[styles.row, alignment === "right" && styles.rowReversed]}>
      {alignment === "left" ? <MessageAuthor /> : null}
      <View style={alignment === "right" ? styles.right : styles.left}>
        <View ref={contextMenuAnchorRef}>
          <MessageContent
            backgroundColor={
              isMyMessage ? semantics.chatBgOutgoing : semantics.chatBgIncoming
            }
          />
        </View>
        <ReactionListBottom type="clustered" />
        <MessageFooter date={date} />
      </View>
    </View>
  );
};

const overrides = { MessageItemView: PlainMessageItemView };

export const PlainMessages = ({ children }: { children: React.ReactNode }) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);

const styles = StyleSheet.create({
  left: { alignItems: "flex-start" },
  right: { alignItems: "flex-end" },
  row: { alignItems: "flex-end", flexDirection: "row", gap: 8 },
  rowReversed: { flexDirection: "row-reverse" },
});
```

`MessageContent` handles the presses, so the long press menu keeps working. The parts and their props are on [Message UI components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/message-ui-components/), and [A custom MessageItemView](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overriding-components/#a-custom-messageitemview) shows another one.

## Override paths

The default view renders these keys. Set them with `WithComponents`.

| Override key          | Renders                                                              | Inside it                                                                                                                                       |
| --------------------- | -------------------------------------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------- |
| `MessageAuthor`       | the sender's avatar, on messages aligned left                        |                                                                                                                                                 |
| `MessageHeader`       | the marks above the bubble                                           | `MessagePinnedHeader`, `MessageReminderHeader`, `MessageSavedForLaterHeader`, `SentToChannelHeader`                                             |
| `ReactionListTop`     | the reactions above the bubble, with `reactionListPosition="top"`    | `ReactionListClustered`, `ReactionListItem`, `ReactionListCountItem`                                                                            |
| `MessageContent`      | the bubble and its content                                           | `Reply`, `Gallery`, `FileAttachmentGroup`, `Attachment`, `StreamingMessageView`, `MessageLocation`, `MessageText` (when set), the content slots |
| `MessageError`        | the error badge on a failed or error message                         |                                                                                                                                                 |
| `MessageReplies`      | the replies button, outside a thread                                 | `MessageRepliesAvatars`                                                                                                                         |
| `ReactionListBottom`  | the reactions under the bubble, with `reactionListPosition="bottom"` | `ReactionListClustered`, `ReactionListItem`                                                                                                     |
| `MessageFooter`       | the sender's name, the status, the time and "Edited"                 | `MessageStatus`, `MessageTimestamp`                                                                                                             |
| `MessageDeleted`      | a deleted message, in place of all the above except `MessageAuthor`  | `MessageFooter`                                                                                                                                 |
| `MessageSpacer`       | last in the message row, outside the bubble                          |                                                                                                                                                 |
| `MessageSwipeContent` | the icon revealed while the user swipes the message                  |                                                                                                                                                 |

`FileAttachmentGroup` renders each file through the `Attachment` key, and `Attachment` picks `AudioAttachment`, `FileAttachment`, `Gallery`, `Giphy`, `UrlPreview`, `URLPreviewCompact` or `UnsupportedAttachment`. The attachments are on [Attachments](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/attachments/), and the reactions on [Reaction components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/reaction-components/). A poll renders `Poll`, which takes the `PollContent` key; see [Poll components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/poll-components/).

## MessageItemView props

The SDK renders the view with no props. The default `MessageItemView` reads each of these from a context, and a prop wins over it.

| Prop                          | Type                                                                            | Default                          | Description                                                                                                                                           |
| ----------------------------- | ------------------------------------------------------------------------------- | -------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------- |
| `alignment`                   | `Alignment`                                                                     | from `MessageContext`            | `'left'` puts the avatar first and the bubble at the start; `'right'` reverses the row.                                                               |
| `channel`                     | `Channel`                                                                       | from `MessageContext`            | The message's channel, passed to `customMessageSwipeAction`.                                                                                          |
| `contextMenuAnchorRef`        | `React.RefObject<ReactNativeElement \| null>`                                   | from `MessageContext`            | Attached to the view around `MessageContent`, which the message menu lines up with.                                                                   |
| `customMessageSwipeAction`    | `({ channel, message, }: { channel: Channel; message: LocalMessage; }) => void` | from `MessagesContext`           | Called when the user swipes the message, in place of quoting it.                                                                                      |
| `enableMessageGroupingByUser` | `boolean`                                                                       | from `MessagesContext`           | Not used by the view.                                                                                                                                 |
| `enableSwipeToReply`          | `boolean`                                                                       | from `MessagesContext`           | Lets the user swipe the message to quote it. Deleted messages can't be swiped.                                                                        |
| `groupStyles`                 | `string[]`                                                                      | from `MessageContext`            | The message's place in its group, passed to `MessageDeleted`.                                                                                         |
| `hasAttachmentActions`        | `boolean`                                                                       | from `MessageContext`            | Whether an attachment has actions. With it, the view treats the message as having no quoted message when it picks the bubble's background and border. |
| `isMyMessage`                 | `boolean`                                                                       | from `MessageContext`            | Picks the outgoing or incoming bubble color.                                                                                                          |
| `lastGroupMessage`            | `boolean`                                                                       | from `MessageContext`            | The view re-renders when it changes.                                                                                                                  |
| `message`                     | `LocalMessage`                                                                  | from `MessageContext`            | The message, passed to `customMessageSwipeAction` and quoted on swipe. The parts read the message from `MessageContext`.                              |
| `messageSwipeToReplyHitSlop`  | `RectOrSize`                                                                    | the screen's width on both sides | The hit slop of the swipe to reply gesture.                                                                                                           |
| `myMessageTheme`              | `DeepPartial<Theme>`                                                            | from `MessagesContext`           | The view re-renders when it changes.                                                                                                                  |
| `onlyEmojis`                  | `boolean`                                                                       | from `MessageContext`            | With it, and no quoted message, the bubble has no background and no border.                                                                           |
| `otherAttachments`            | `Attachment[]`                                                                  | from `MessageContext`            | A Giphy or Imgur attachment here, without a quoted message, gets a transparent bubble.                                                                |
| `reactionListPosition`        | `"bottom" \| "top"`                                                             | from `MessagesContext`           | Renders `ReactionListTop` above the bubble, or `ReactionListBottom` under it.                                                                         |
| `reactionListType`            | `"clustered" \| "segmented"`                                                    | from `MessagesContext`           | Passed to the reaction list as `type`.                                                                                                                |
| `setQuotedMessage`            | `(quotedMessage: LocalMessage \| null) => void`                                 | from `MessageContext`            | Quotes the message when the user swipes it.                                                                                                           |
| `thread`                      | `Thread`                                                                        | from `ThreadContext`             | Inside a thread, the replies button doesn't render.                                                                                                   |

## MessageContent props

`MessageContent` renders the bubble: a `Pressable` that reports presses with the `messageContent` emitter, the bubble's background and corners, the content slots, and the parts in `messageContentOrder`. A quoted message renders `Reply`, and pressing it calls `goToMessage`. The text of an AI-generated message renders `StreamingMessageView` in place of the text. A location renders the `MessageLocation` key, which has no default.

| Prop                                 | Type                                                                  | Default                                                                                                                                                                    | Description                                                                                                                 |
| ------------------------------------ | --------------------------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | --------------------------------------------------------------------------------------------------------------------------- |
| `additionalPressableProps`           | `Omit<PressableProps, "style">`                                       | from `MessagesContext`                                                                                                                                                     | Props for the bubble's `Pressable`, applied after its handlers. `onPressOut` is called after the list re-enables scrolling. |
| `alignment`                          | `Alignment`                                                           | from `MessageContext`                                                                                                                                                      | Puts the bubble's tail on the right or the left corner.                                                                     |
| `backgroundColor`                    | `ColorValue`                                                          |                                                                                                                                                                            | The bubble's color. `MessageItemView` passes the outgoing or incoming color, or `transparent`.                              |
| `enableMessageGroupingByUser`        | `boolean`                                                             | from `MessagesContext`                                                                                                                                                     | With it, the newest message uses the `lastMessageContainer` style.                                                          |
| `goToMessage`                        | `(messageId: string) => void`                                         | from `MessageContext`                                                                                                                                                      | Called with the quoted message's ID when the user presses it. Without it, the quoted message can't be pressed.              |
| `groupStyles`                        | `string[]`                                                            | from `MessageContext`                                                                                                                                                      | A `bottom` or `single` message gets a tail corner.                                                                          |
| `hasInteractiveAccessibilityContent` | `boolean`                                                             | from `MessageContext`                                                                                                                                                      | Lets screen readers reach the parts one by one instead of the bubble as a whole.                                            |
| `hidePaddingBottom`                  | `boolean`                                                             | `true` when the bubble holds a poll, a Giphy or Imgur attachment without a quoted message, or nothing but one image or video, one file, or text, or when it ends with text | Removes the bubble's bottom padding.                                                                                        |
| `hidePaddingHorizontal`              | `boolean`                                                             | `true` when the bubble holds a poll, a Giphy or Imgur attachment without a quoted message, or nothing but one image or video or one file                                   | Removes the bubble's side padding.                                                                                          |
| `hidePaddingTop`                     | `boolean`                                                             | `true` when the bubble holds a poll, a Giphy or Imgur attachment without a quoted message, or nothing but one image or video, one file, or text                            | Removes the bubble's top padding.                                                                                           |
| `isAttachmentEqual`                  | `(prevAttachment: Attachment, nextAttachment: Attachment) => boolean` | from `MessagesContext`                                                                                                                                                     | An extra check when the bubble re-renders.                                                                                  |
| `isMyMessage`                        | `boolean`                                                             | from `MessageContext`                                                                                                                                                      | Picks the accessibility label: "from you" or "from" the sender.                                                             |
| `isSingleFile`                       | `boolean`                                                             |                                                                                                                                                                            | Not used.                                                                                                                   |
| `isVeryLastMessage`                  | `boolean`                                                             |                                                                                                                                                                            | Passed by `MessageItemView`. With grouping on, the newest message uses the `lastMessageContainer` style.                    |
| `message`                            | `LocalMessage`                                                        | from `MessageContext`                                                                                                                                                      | The message.                                                                                                                |
| `messageContentOrder`                | `MessageContentType[]`                                                | from `MessageContext`                                                                                                                                                      | The parts to render, in order.                                                                                              |
| `messageGroupedSingleOrBottom`       | `boolean`                                                             | `false`                                                                                                                                                                    | Passed by `MessageItemView`. Picks the `messageGroupedSingleOrBottomContainer` style over `messageGroupedTopContainer`.     |
| `myMessageTheme`                     | `DeepPartial<Theme>`                                                  | from `MessagesContext`                                                                                                                                                     | The bubble re-renders when it changes.                                                                                      |
| `noBorder`                           | `boolean`                                                             |                                                                                                                                                                            | Removes the bubble's border.                                                                                                |
| `onLongPress`                        | `(payload: PressableHandlerPayload) => void`                          | from `MessageContext`                                                                                                                                                      | Called on a long press on the bubble or the quoted message.                                                                 |
| `onPress`                            | `(payload: MessagePressableHandlerPayload) => void`                   | from `MessageContext`                                                                                                                                                      | Called on a press on the bubble or the quoted message.                                                                      |
| `onPressIn`                          | `((payload: PressableHandlerPayload) => void) \| null`                | from `MessageContext`                                                                                                                                                      | Called when a press on the bubble or the quoted message starts.                                                             |
| `otherAttachments`                   | `Attachment[]`                                                        | from `MessageContext`                                                                                                                                                      | The attachments of the `attachments` part. When the first has actions, the text isn't shown.                                |
| `preventPress`                       | `boolean`                                                             | from `MessageContext`                                                                                                                                                      | Turns off presses on the bubble and the quoted message.                                                                     |
| `t`                                  | `StreamTFunction`                                                     | from `TranslationContext`                                                                                                                                                  | The bubble re-renders when it changes.                                                                                      |

## Content slots

These override keys have no default. Each renders inside the bubble when set, and receives no props: read what you need from `useMessageContext()`.

| Override key                 | Where it renders                     |
| ---------------------------- | ------------------------------------ |
| `MessageContentTopView`      | above the content                    |
| `MessageContentBottomView`   | under the content                    |
| `MessageContentLeadingView`  | before the content, in a row with it |
| `MessageContentTrailingView` | after the content, in a row with it  |

`MessageSpacer` renders last in the message row, beside the content and outside the bubble, and receives no props either. `MessageSwipeContent` takes no props: it's the round reply icon that appears beside the message while the user swipes it.

## Related hooks

- `useMessageContext()` reads the message and its handlers.
- `useMessagesContext()` reads the settings of `Channel` or `Thread`, such as `reactionListPosition`.
- `useComponentsContext()` reads the override keys, for a part that renders another part.
- `useTheme()` reads the theme. The view's styles are under `theme.messageItemView`.

---

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