# Message UI

> **Info:** This is release candidate documentation for **Stream Chat React SDK v15**. For the latest stable version, see the [latest version (v14)](https://getstream.io/chat/docs/sdk/react/).

The message UI is the component that draws one message. [`Message`](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/message/) renders the `MessageUI` override with no props, and the UI reads the message and its handlers from [`MessageContext`](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/messagecontext/). The default is `MessageUI`. [A message](https://getstream.io/chat/docs/sdk/react/v15/ui/components/message-list-ui/#a-message) lists the parts it's made of, and [A custom MessageUI](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/overriding-components/#a-custom-messageui) explains how a replacement applies.

## Best practices

- Build a custom message UI from the exported parts, such as `MessageText`, `MessageTimestamp` and `Attachment`. They read the same context, and most need no props; `Attachment` takes the attachments to render.
- Handle the kinds of message your app has. The default covers deleted, blocked, bounced and failed messages, polls and quoted messages. System messages go to the `MessageSystem` override instead.
- Set `VirtualMessage` only when `VirtualizedMessageList` needs a different UI. There it wins over `MessageUI`.
- Declare the `overrides` object once, outside the component, so every message doesn't re-render with each render of the parent.

## Basic usage

The default `MessageUI` also takes any `MessageContext` value as a prop, and a prop wins over the context. A wrapper registered as the override changes one value for every message. This one shows the sender's avatar on every message, the user's own included:

```tsx
import { MessageUI, WithComponents } from "stream-chat-react";

const MessageUIWithAllAvatars = () => <MessageUI showAvatar />;

const overrides = { MessageUI: MessageUIWithAllAvatars };

export const App = () => (
  <WithComponents overrides={overrides}>
    {/* the rest of the app */}
  </WithComponents>
);
```

## UI customization

A message UI of your own composes the parts it needs. This one keeps the actions, a poll, a quoted message, the attachments, reactions, the replies button, the time and the delivery status:

```tsx
import {
  Attachment,
  isMessageDeleted,
  MessageActions,
  MessageDeletedBubble,
  MessageReactions,
  MessageRepliesCountButton,
  MessageStatus,
  MessageText,
  MessageTimestamp,
  Poll,
  QuotedMessage,
  useChatContext,
  useMessageContext,
} from "stream-chat-react";

export const CustomMessageUI = () => {
  const { client } = useChatContext();
  const { handleAction, message } = useMessageContext();
  const poll = message.poll_id
    ? client.polls.fromState(message.poll_id)
    : undefined;

  if (isMessageDeleted(message)) return <MessageDeletedBubble />;

  return (
    <div className="custom-message">
      <MessageActions />
      {poll && <Poll poll={poll} />}
      {message.quoted_message && <QuotedMessage />}
      {message.attachments?.length ? (
        <Attachment
          actionHandler={handleAction}
          attachments={message.attachments}
        />
      ) : null}
      <MessageText />
      <MessageReactions />
      <MessageRepliesCountButton
        reply_count={message.reply_count}
        thread_participants={message.thread_participants}
      />
      <MessageTimestamp />
      <MessageStatus />
    </div>
  );
};
```

`MessageRepliesCountButton` renders nothing for a message without replies. When clicked, it calls its `onClick` prop if you pass one, and otherwise the message's `handleOpenThread`, which calls `Message`'s `openThread` prop when set and opens the thread through workspace navigation otherwise. The parts and their props are on [Message UI components](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/message-ui-components/). A shared location travels in `message.shared_location`, not in `message.attachments`; [Attachments](https://getstream.io/chat/docs/sdk/react/v15/component-reference/message/attachments/#basic-usage) shows how to pass both.

## Override paths

| To change                                          | Set                                                                                                                              |
| -------------------------------------------------- | -------------------------------------------------------------------------------------------------------------------------------- |
| Every message, in both lists and a thread's parent | the `MessageUI` key                                                                                                              |
| Every message in `VirtualizedMessageList` only     | the `VirtualMessage` key                                                                                                         |
| One part of the default `MessageUI`                | that part's key, from the table in [A message](https://getstream.io/chat/docs/sdk/react/v15/ui/components/message-list-ui/#a-message)                |
| A deleted message, replacing the whole UI          | the `MessageDeleted` key, which receives `{ message }` and has no default                                                        |
| A system message                                   | the `MessageSystem` key                                                                                                          |
| The parent message above a thread's replies        | the `ThreadHead` key, typed with the `Message` props and given only `message`                                                    |
| The items of the actions menu                      | the `messageActionSet` prop of `MessageActions`, see [Actions](https://getstream.io/chat/docs/sdk/react/v15/ui/customizing/actions/#message-actions) |

Set the keys with `WithComponents`.

## Props

The SDK renders the message UI with no props. The default `MessageUI` accepts `Partial<MessageContextValue>`, exported as `MessageUIComponentProps`, and merges it over the context. These are the values it reads:

| Prop                   | Type                                  | Default      | Description                                                                                                    |
| ---------------------- | ------------------------------------- | ------------ | -------------------------------------------------------------------------------------------------------------- |
| `endOfGroup`           | `boolean`                             |              | With `groupedByUser`, marks the last message of a group, the only one that shows the time and status.          |
| `firstOfGroup`         | `boolean`                             |              | Adds the `str-chat__virtual-message__wrapper--first` class.                                                    |
| `groupedByUser`        | `boolean`                             |              | Adds the `str-chat__virtual-message__wrapper--group` class, and hides the time and status unless `endOfGroup`. |
| `handleAction`         | `ActionHandlerReturnType`             | from context | Passed to `Attachment` for the attachments' actions.                                                           |
| `highlighted`          | `boolean`                             | from context | Adds the `str-chat__message--highlighted` class.                                                               |
| `isMessageAIGenerated` | `(message: LocalMessage) => boolean`  | from context | Renders the text of an AI-generated message with `StreamedMessageText`, and hides its edited mark.             |
| `isMyMessage`          | `() => boolean`                       | from context | Adds the `str-chat__message--me` or `str-chat__message--other` class.                                          |
| `message`              | `LocalMessage`                        | from context | The message to draw.                                                                                           |
| `onUserClick`          | `ReactEventHandler`                   | from context | Attached to the avatar.                                                                                        |
| `onUserHover`          | `ReactEventHandler`                   | from context | Attached to the avatar.                                                                                        |
| `renderText`           | `RenderTextFunction`                  | from context | Passed to `MessageText` or `StreamedMessageText`.                                                              |
| `showAvatar`           | `boolean \| 'incoming' \| 'outgoing'` | `'incoming'` | Which messages get the avatar column: all (`true`), none (`false`), other users' or the user's own.            |

The default `MessageUI` re-renders when the message, its read and delivery state, its highlight or its grouping changes. Give the other props values that don't change, such as a `renderText` declared outside the component.

## Hooks

- `useMessageContext()` reads the message and its handlers.
- `useComponentContext()` reads the override keys, for a part that renders another part.

---

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