Message UI components
The default MessageItemView is built from parts, and stream-chat-react-native exports them for a message view 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, except MessageTextContainer, whose text the MessageText key replaces.
Best practices
- Compose these parts instead of rebuilding them. They handle states that are easy to miss, such as a message that is still sending, a failed message, an edited one or a reply sent to the channel.
- Replace one part through its override key, and keep the rest of the default view.
- Wrap the exported part when you only add to it, as the sample below does, so its own behavior stays.
- Change the actions in the message menu through
messageActionsonChannel, not through these parts. See Message actions.
Basic usage
This replacement keeps the default status icon and adds "Read" once another member has read the message:
import { StyleSheet, Text } from "react-native";
import {
MessageStatus,
type MessageStatusProps,
useIsMessageReadByOthers,
useMessageContext,
WithComponents,
} from "stream-chat-react-native";
const MessageStatusWithText = (props: MessageStatusProps) => {
const { message } = useMessageContext();
const read = useIsMessageReadByOthers({ message });
return (
<>
<MessageStatus {...props} />
{read ? <Text style={styles.read}>Read</Text> : null}
</>
);
};
const overrides = { MessageStatus: MessageStatusWithText };
export const MessagesWithReadText = ({
children,
}: {
children: React.ReactNode;
}) => <WithComponents overrides={overrides}>{children}</WithComponents>;
const styles = StyleSheet.create({
read: { fontSize: 12 },
});Status indicators builds more of them.
Available components
| Component | Renders | Exported |
|---|---|---|
MessageAuthor |
the sender's avatar, or a spacer of the same width | yes |
MessageHeader |
the reminder, pinned and sent-to-channel marks above the bubble | yes |
MessagePinnedHeader |
"Pinned by" and the name, or "You" | yes |
MessageReminderHeader |
"Reminder set" or "Reminder overdue", with the time left | yes |
MessageSavedForLaterHeader |
"Saved For Later" | yes |
SentToChannelHeader |
"Also sent in channel" or "Replied to a thread", with View | yes |
MessageTextContainer |
the message's text, as Markdown | yes, not an override key |
MessageFooter |
the sender's name, the status, the time and "Edited" | yes |
MessageTimestamp |
the time | yes |
MessageStatus |
the delivery status icon of the user's own messages | yes |
MessageReplies |
the replies button, with the participants' avatars | yes |
MessageRepliesAvatars |
the avatars of up to three thread participants | yes |
MessageDeleted |
"Message deleted" and the footer | yes |
MessageError |
the error badge on a failed or error message | yes |
MessageBlocked |
a message blocked by moderation, in place of the message view | yes |
MessageBounce |
the dialog of a bounced message | yes |
MessageSystem |
a system message, in place of Message |
yes |
StreamingMessageView |
the text of an AI-generated message, revealed as it streams | yes |
MessageAuthor
Renders the sender's avatar on messages aligned left. Where the avatar doesn't show, it renders an empty view of the same size, so the bubbles of a group stay aligned. It re-renders only when lastGroupMessage or the sender's ID, name or image changes.
| Prop | Type | Default | Description |
|---|---|---|---|
lastGroupMessage |
boolean |
from MessageContext |
Shows the avatar when showAvatar isn't set. |
message |
LocalMessage |
from MessageContext |
The message whose sender is shown. |
showAvatar |
boolean |
from MessageContext |
Shows or hides the avatar, whatever the group. |
size |
"sm" | "md" | "lg" | "xl" | "xs" | "2xl" |
'md' |
The avatar's size. |
MessageHeader
Renders, above the bubble, the MessageReminderHeader override when the message has a reminder with a time, or the MessageSavedForLaterHeader override when it has one without; the MessagePinnedHeader override for a pinned message; and the SentToChannelHeader override for a reply also sent to the channel. It renders nothing when none applies. It reads the message and its reminder from context.
| Prop | Type | Default | Description |
|---|---|---|---|
message |
LocalMessage |
from MessageContext |
Passed to MessagePinnedHeader. Which marks show still follows the message in MessageContext. |
MessagePinnedHeader
Renders "Pinned by" and the name of who pinned the message, or "You". It renders nothing for a message that isn't pinned.
| Prop | Type | Default | Description |
|---|---|---|---|
message |
LocalMessage |
from MessageContext |
The message. |
MessageReminderHeader
Renders "Reminder set" and the time left, from the duration.messageReminder translation key, or "Reminder overdue". It reads the reminder of the message in MessageContext.
| Prop | Type | Default | Description |
|---|---|---|---|
isReminderTimeLeft |
boolean |
true while timeLeftMs is above 0 |
Picks "Reminder set" over "Reminder overdue". |
timeLeftMs |
number |
the reminder's timeLeftMs |
The time until the reminder, in milliseconds. |
MessageSavedForLaterHeader
Renders "Saved For Later" with a bookmark icon. It takes no props. The exported MessageSavedForLaterHeaderProps type lists message, which the component doesn't read.
SentToChannelHeader
Renders "Also sent in channel" on a reply shown in a thread, and "Replied to a thread" on the same reply shown in the channel. With onAlsoSentToChannelHeaderPress set on Channel or Thread, it adds View: in a thread, pressing it calls the handler with the message's ID; in a channel, with the message's ID and the reply's Thread, loading the parent message first when it isn't loaded.
| Prop | Type | Default | Description |
|---|---|---|---|
onPress |
() => void |
calls onAlsoSentToChannelHeaderPress as described above |
Called when the user presses View. |
showViewText |
boolean |
true when onAlsoSentToChannelHeaderPress is set |
Shows View. |
thread |
Thread |
from ThreadContext |
Picks the text: "Also sent in channel" inside a thread. |
MessageTextContainer
Renders the message's text as Markdown, with mentions and links that can be pressed. When the message has an auto-translation into the user's language, it renders that instead. It renders nothing for a message without text. With the MessageText override set, it renders that inside its container instead, with its own props, renderText (the exported function it renders with by default) and theme; see Overriding components.
| Prop | Type | Default | Description |
|---|---|---|---|
hasInteractiveAccessibilityContent |
boolean |
from MessageContext |
Makes the text its own accessibility element. |
isMyMessage |
boolean |
from MessageContext |
Picks the colors of the user's own messages. |
markdownRules |
MarkdownRules |
from MessagesContext |
simple-markdown rules merged over the SDK's. |
markdownStyles |
MarkdownStyle |
Styles merged over theme.messageItemView.content.markdown. |
|
message |
LocalMessage |
from MessageContext |
The message whose text renders. |
messageOverlay |
boolean |
Set when the text renders in the message menu. The text then re-renders when markdownStyles change. |
|
messageTextNumberOfLines |
number |
from MessagesContext |
Truncates the text to this many lines, and renders only the first paragraph. |
myMessageTheme |
DeepPartial<Theme> |
from MessagesContext |
The text re-renders when it changes. |
onLongPress |
(payload: PressableHandlerPayload) => void |
from MessageContext |
Called on a long press on the text. |
onlyEmojis |
boolean |
from MessageContext |
Applies the onlyEmojiMarkdown style. |
onPress |
(payload: MessagePressableHandlerPayload) => void |
from MessageContext |
Called on a press on a link or a mention, with the textLink or textMention emitter. |
preventPress |
boolean |
from MessageContext |
Turns off presses on the text. |
styles |
Partial<{ textContainer: StyleProp<ViewStyle>; }> |
Style of the view around the text. |
MessageFooter
Renders, under the bubble, the sender's name on other users' messages, except in a channel with exactly two members, the MessageStatus override when showMessageStatus is set, the MessageTimestamp override, and "Edited" on an edited message that isn't AI-generated. It renders nothing for a message the server accepted that isn't the last of its group.
| Prop | Type | Default | Description |
|---|---|---|---|
alignment |
Alignment |
from MessageContext |
The sender's name shows on 'left' messages only. |
date |
string | Date |
The time to show, passed to MessageTimestamp as timestamp. MessageItemView passes the message's created_at. |
|
formattedDate |
string | Date |
Text shown in place of the formatted date. |
|
lastGroupMessage |
boolean |
from MessageContext |
With false, the footer shows only on a message that is sending or failed. |
message |
LocalMessage |
from MessageContext |
The message. |
otherAttachments |
Attachment[] |
Not used. | |
showMessageStatus |
boolean |
from MessageContext |
Shows MessageStatus. |
MessageTimestamp
Renders a time formatted with a translation key. It renders nothing when there's no time to show.
| Prop | Type | Default | Description |
|---|---|---|---|
formattedDate |
string | Date |
Text shown as is, in place of the formatted timestamp. |
|
tDateTimeParser |
TDateTimeParser |
from TranslationContext |
Parses the time for formatting. |
timestamp |
string | Date |
The time to format. | |
timestampTranslationKey |
string |
'timestamp.MessageTimestamp' |
The translation key whose value is the format. See Date and time formatting. |
MessageStatus
Renders the status of one of the user's own messages: a clock while sending, one check once the server accepted it, and two checks once it reached or was read by another member, in a different color when read. It renders nothing for a failed or error message. Read state, unread and receipts explains where the receipts come from.
| Prop | Type | Default | Description |
|---|---|---|---|
delivered |
boolean |
useIsMessageDeliveredToOthers({ message }) |
Whether the message reached at least one other member. |
message |
LocalMessage |
from MessageContext |
The message. |
read |
boolean |
useIsMessageReadByOthers({ message }) |
Whether at least one other member read the message. |
MessageReplies
Renders "1 Reply" or "5 Replies", the MessageRepliesAvatars override and a connector line. It renders nothing for a message without replies. Pressing it reports the messageReplies emitter with onOpenThread as the default handler, so it calls the list's onThreadSelect. MessageItemView doesn't render it inside a thread; a view of your own that renders it checks useThreadContext().thread itself.
| Prop | Type | Default | Description |
|---|---|---|---|
alignment |
Alignment |
from MessageContext |
Puts the connector on the left or the right. |
isMyMessage |
boolean |
from MessageContext |
Picks the connector's color. |
message |
LocalMessage |
from MessageContext |
The message whose reply_count shows. |
onLongPress |
(payload: PressableHandlerPayload) => void |
from MessageContext |
Called on a long press. |
onOpenThread |
() => void |
from MessageContext |
The default handler of a press. |
onPress |
(payload: MessagePressableHandlerPayload) => void |
from MessageContext |
Called on a press. |
onPressIn |
((payload: PressableHandlerPayload) => void) | null |
from MessageContext |
Called when a press starts. |
preventPress |
boolean |
from MessageContext |
Turns off presses. |
t |
StreamTFunction |
from TranslationContext |
Translates the label. |
MessageRepliesAvatars
Renders the avatars of up to three of the message's thread_participants.
| Prop | Type | Default | Description |
|---|---|---|---|
message |
LocalMessage |
from MessageContext |
The message whose participants show. |
MessageDeleted
Renders "Message deleted" in a bubble, and the MessageFooter override under it. MessageItemView renders it in place of the headers, the bubble, the reactions and the replies of a deleted message.
| Prop | Type | Default | Description |
|---|---|---|---|
alignment |
Alignment |
from MessageContext |
Aligns the bubble left or right. |
date |
string | Date |
Passed to MessageFooter. |
|
groupStyle |
string |
required | The alignment and group, such as 'left_bottom'. left_bottom, left_single, right_bottom and right_single give the bubble its tail corner. |
message |
LocalMessage |
from MessageContext |
The component re-renders when its type, text, status, reply count or pinned state changes. |
MessageError
Renders the error badge at the top corner of a failed or error message's bubble. It takes no props.
MessageBlocked
Renders the text of a message that moderation blocked, centered in a pill. Message renders it in place of the message view.
| Prop | Type | Default | Description |
|---|---|---|---|
message |
LocalMessage |
required | The blocked message. Its text is shown. |
style |
StyleProp<ViewStyle> |
Style of the container. |
MessageBounce
Shows the dialog of a message that moderation bounced: "Send Anyway" resends it, "Edit Message" puts it in the composer, and "Delete Message" removes it from the list. It renders no view of its own, and opens a native alert when it renders. Message renders it when the user presses or long presses a bounced message.
| Prop | Type | Default | Description |
|---|---|---|---|
message |
LocalMessage |
from MessageContext |
The bounced message. |
removeMessage |
(message: { id: string; parent_id?: string; }) => Promise<void> |
from useMessageOperations() |
Removes the message locally, for "Delete Message". |
retrySendMessage |
(message: LocalMessage) => Promise<void> |
from useMessageOperations() |
Resends the message, for "Send Anyway". |
setEditingState |
(message?: LocalMessage) => void |
from MessageComposerAPIContext |
Puts the message in the composer, for "Edit Message". |
setIsBounceDialogOpen |
React.Dispatch<React.SetStateAction<boolean>> |
required | Closes the dialog. Each button calls it with false. |
Replacing the bounce alert shows a replacement.
MessageSystem
Renders a system message, such as "Cleo joined the channel", with its time from the timestamp.MessageSystem translation key. The list renders it in place of Message for a message of type system.
| Prop | Type | Default | Description |
|---|---|---|---|
message |
LocalMessage |
required | The system message. |
style |
StyleProp<ViewStyle> |
Style of the container. The list passes theme.messageList.messageContainer. |
StreamingMessageView
Renders the text of an AI-generated message with MessageTextContainer, revealing new text a few letters at a time as the message updates. The text the message had when it mounted shows at once. MessageContent renders it in place of the text when isMessageAIGenerated on Chat returns true for the message. StreamingMessageView covers the AI setup.
| Prop | Type | Default | Description |
|---|---|---|---|
letterInterval |
number |
0 |
The delay between steps, in milliseconds. |
message |
LocalMessage |
from MessageContext |
The message whose text streams. |
renderingLetterCount |
number |
2 |
The number of letters revealed at each step. |
Related hooks
useMessageContext()reads the message the parts render.useIsMessageReadByOthers({ message })anduseIsMessageDeliveredToOthers({ message })give the receiptsMessageStatusshows, anduseMessageReadDataanduseMessageDeliveredDatawho read the message and who received it. See Message hooks.useMessageReminder(messageId)returns the reminderMessageHeaderreads.useStreamingMessage({ text })reveals text the wayStreamingMessageViewdoes.