Message UI components

The default MessageUI is built from parts, and stream-chat-react exports them for a message UI of your own. Each part reads the message from MessageContext, so most need no props inside a message. Each is an override key of the same name. Message UI shows where each part sits.

Best practices

  • Compose these parts instead of rebuilding them. They handle states that are easy to miss, such as a failed send, a thread reply or a message without text.
  • Replace one part through its override key, and keep the rest of the default MessageUI.
  • To change the action menu, change the action set, not the component. Actions explains how.

Available UI components

Component Renders Props
MessageActions The quick actions next to the message and the actions menu. Below
MessageAlsoSentInChannelIndicator "Also sent in channel" on a thread reply, or "Replied to a thread" in the channel, with a View button that jumps there. onView, to replace what View does
MessageBlocked "Message was blocked by moderation policies", in place of a removed or shadowed message. none
MessageBouncePrompt The prompt for a bounced message, see MessageBounceContext. children, to replace the title and description
MessageBubbleContent What the bubble holds: the quoted message, the poll, the attachments and the text. Below
MessageDeletedBubble "Message deleted", in place of the bubble. none
MessageEditedIndicator "Edited", with the edit time in a tooltip. Below
MessageRepliesCountButton The reply count and the avatars of the thread's participants. Clicking it opens the thread. reply_count, thread_participants, onClick, labelSingle, labelPlural
MessageStatus Sending, sent, delivered and read, on the user's own messages. Below
MessageText The text, through renderText, or the translation. message, renderText, customWrapperClass, customInnerClass
MessageTimestamp The time the message was sent. message, customClass, calendar, calendarFormats, format
MessageTranslationIndicator "Translated from …", with a button to show the original. message
PinIndicator "Pinned by …" above the message. message, required to render anything
QuotedMessage The message this one quotes. Clicking it jumps to the quoted message. renderText
ReminderNotification The reminder set on the message, or "Saved for later". reminder, required to render anything
StreamedMessageText The text of an AI-generated message, a few letters at a time. It renders the text through the MessageText key. message, renderText, renderingLetterCount, streamingLetterIntervalMs

A message prop replaces the message from the context. With one, MessageTimestamp also renders outside a message, for example in an override of the gallery header's time; without one, it throws outside a MessageProvider. Timestamp, the component MessageTimestamp and MessageEditedIndicator render the time with, isn't exported; replace it with the Timestamp override key.

For ReactionSelector, MessageReactions and MessageReactionsDetail, see Reaction components. For Attachment, see Attachments.

MessageActions props

Prop Type Default Description
disableBaseMessageActionSetFilter boolean false Skips the base filter, which removes what the user can't do or what doesn't apply to the message. The items' isVisible rules still apply.
messageActionSet MessageActionSetItem[] defaultMessageActionSet The actions. Each item has a Component and a placement: 'quick', 'dropdown' or 'quick-dropdown-toggle'. Every item but the toggle has a type too, and can have an isVisible rule: see Rules on the items.

The default set, and how to add, remove or replace an action, are on Actions. useBaseMessageActionSetFilter(set) runs the same filter on a set of your own.

MessageBubbleContent props

Prop Type Default Description
messageBubbleContentSet MessageBubbleContentSetItem[] defaultMessageBubbleContentSet The content, in the order it renders.

It renders the items whose isVisible holds for the message. Each item has these fields:

Field Type Description
type string Names the content. Unique within a set.
Component React.ComponentType The content. It renders without props; read the message with useMessageContext().
isVisible (state: MessageBubbleContentVisibilityFilterParams) => boolean Whether the content shows for the message.

MessageBubbleContentVisibilityFilterParams holds the message, and isAIGenerated: whether isMessageAIGenerated marks the message as AI generated. Bubble content lists the default items and when each one shows.

MessageEditedIndicator props

MessageEditedIndicator renders only for a message with message_text_updated_at. The default MessageUI also leaves it out for AI-generated messages.

Prop Type Default Description
calendar boolean | null from timestamp.MessageTimestamp Writes the edit time relative to today, such as "Yesterday at 14:32".
calendarFormats Record<string, string> | string from timestamp.MessageTimestamp The calendar's formats, used with calendar.
customClass string 'str-chat__message-edited-indicator' Replaces the class of the outer span.
format string from timestamp.MessageTimestamp A Day.js format for the edit time, such as HH:mm.
message LocalMessage the context's message The message whose edit time to show.

The edit time in the tooltip goes through formatDate from the context first, when the list has one. Date and time formatting covers the keys and formats.

MessageStatus props

MessageStatus renders on the user's own messages only, and not on failed or error messages. In a thread it shows only "sending". "Sent" shows on the user's latest message, or on every own message with returnAllReadData.

Prop Type Default Description
MessageDeliveredStatus ComponentType a double check Rendered when the message reached another member's device and nobody else has read it.
MessageReadStatus ComponentType a double check, with a count when several read it Rendered when another member read the message. The default tooltip lists the readers.
MessageSendingStatus ComponentType a clock Rendered while the message is sending.
MessageSentStatus ComponentType a check Rendered when the server has the message and no one else has received it yet.
messageType string 'simple' Used in the class names, as in str-chat__message-simple-status.
tooltipUserNameMapper (user: UserResponse) => string user.name || user.id Turns each reader into the name the read tooltip shows.

This replacement shows only first names in the read tooltip:

import type { TooltipUsernameMapper } from "stream-chat-react";
import { MessageStatus, WithComponents } from "stream-chat-react";

const firstName: TooltipUsernameMapper = (user) =>
  user.name?.split(" ")[0] ?? user.id;

// The SDK renders the `MessageStatus` key without props, so the override passes its own.
const MessageStatusWithFirstNames = () => (
  <MessageStatus tooltipUserNameMapper={firstName} />
);

const overrides = { MessageStatus: MessageStatusWithFirstNames };

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

Read state, unread and receipts explains where the read and delivery state comes from.

Hooks

  • useMessageContext() reads the message the parts render.
  • useMessageAlsoSentInChannelNavigation() gives the jump that the View button of MessageAlsoSentInChannelIndicator makes, for a button of your own.
  • useMessageReminder(messageId) returns the reminder ReminderNotification shows.