Skip to main content

Message UI

How-to Guide for Building a Custom Message#

Using pre-built UI components from the library, the following guide walks you through the process of building a custom Message UI component that looks great and comes packed with functionality. This component must be added to either the Channel or MessageList component via the Message prop.

All of the message UI components in this example have access to the MessageContext, and therefore can call the useMessageContext custom hook. The return value from this hook contains all of the values and functions needed to build a Message UI component.

UI Component Overview#

The custom Message UI component built below imports and uses the following UI components:

  • Attachment - displays the attachments included with a message. See the Attachments section for information on types and props.

  • Avatar - displays the image of the user that sent the message. If the user does not have an image, it will default to the initials of the user's name.

  • MessageOptions - on hover, shows the available options on a message (i.e., react, reply, actions). This component internally renders the MessageActions component, which displays the available actions on a message (ex: edit, flag, pin).

  • MessageRepliesCountButton - displays the number of threaded replies on a message. Clicking the button will call the handleOpenThread function and navigate into a Thread component that lists the replies.

  • MessageStatus - displays message delivery status and shows the users who have read the message.

  • MessageText - formats and renders the message text in markdown using react-markdown. This component also renders QuotedMessage, which provides an additional UI wrapper if the sent message has quoted a previous message.

  • MessageTimestamp - shows the sent time of a message. The default format can be overridden with props.

  • ReactionSelector - allows the connected user to select a reaction on a message. The list of emojis can be customized, but this tutorial uses the default set.

  • SimpleReactionsList - displays a minimal list of the reactions added to a message (alternate option to ReactionsList).

How it Fits Together#

The sample code below assembles the above UI building blocks into a fully featured Message UI component. The UI components allow you to pick the features you wish to employ in your message and orient them in a manner that meets your design specifications. All of the components consume the MessageContext and from pull the necessary data by using the useMessageContext hook.

tip

In advanced use cases, the pre-built, UI components may not provide enough design customization potential. In these situations, we recommend copying the component's functionality and adding your own design and layout.

The Code:#

import React, { useRef } from 'react';
import {
Attachment,
Avatar,
messageHasReactions,
MessageOptions,
MessageRepliesCountButton,
MessageStatus,
MessageText,
MessageTimestamp,
ReactionSelector,
SimpleReactionsList,
useMessageContext,
} from 'stream-chat-react';

import './CustomMessage.scss';

export const CustomMessage = () => {
const {
isReactionEnabled,
message,
reactionSelectorRef,
showDetailedReactions,
} = useMessageContext();

const messageWrapperRef = useRef(null);

const hasReactions = messageHasReactions(message);

return (
<div className='message-wrapper'>
<Avatar image={message.user?.image} />
<div className='message-wrapper-content'>
<MessageOptions displayLeft={false} messageWrapperRef={messageWrapperRef} />
<div className='message-header'>
<div className='message-header-name'>{message.user?.name}</div>
<div className='message-header-timestamp'>
<MessageTimestamp />
</div>
</div>
{showDetailedReactions && isReactionEnabled && (
<ReactionSelector ref={reactionSelectorRef} />
)}
<MessageText />
<MessageStatus />
{message.attachments && <Attachment attachments={message.attachments} />}
{hasReactions && !showDetailedReactions && isReactionEnabled && <SimpleReactionsList />}
<MessageRepliesCountButton reply_count={message.reply_count} />
</div>
</div>
);
};

CustomMessage.scss:

.str-chat__li {
margin: 0px;
padding: 15px;
position: relative;

&:hover {
background: rgba(0, 0, 0, 0.03);
.str-chat__message-text-inner {
background: rgba(0, 0, 0, 0);
}
}
}

.message-wrapper {
display: flex;

&-content {
display: flex;
flex-direction: column;
align-items: flex-start;
width: 100%;
}
}

.message-header {
display: flex;

&-name {
font-family: Helvetica Neue, sans-serif;
font-weight: 500;
font-size: 11px;
line-height: 120%;
color: #858688;
}

&-timestamp {
font-family: Helvetica Neue, sans-serif;
font-size: 11px;
line-height: 120%;
color: #858688;
margin-left: 6px;
}
}

.str-chat__li:hover .str-chat__message-simple__actions {
position: absolute;
top: -14px;
right: 20px;
display: flex;
align-items: center;
justify-content: space-between;
height: 24px;
border-radius: 100px;
background: white;
border: 1px solid #e0e0e0;
box-shadow: 0 2px 1px 0 rgba(0, 0, 0, 0.07);
z-index: 1;
padding: 0 4px 0;

&__action--reactions {
display: flex;
}

&__action--options {
display: flex;
}

&__action--thread {
display: flex;
}
}

.str-chat__message-simple__actions {
margin-top: 0;
}

.str-chat__message-actions-box {
top: initial;
left: -100px;
border-radius: 16px 16px 0 16px;
}

.str-chat__message-text {
display: flex;
width: 100%;
}

.str-chat__message-text-inner {
position: relative;
flex: 1;
display: block;
min-height: 32px;
font-size: 15px;
color: black;
border-radius: 0;
border: 0px;
margin-left: 0;

p {
font-family: Helvetica Neue, sans-serif;
font-size: 15px;
line-height: 18px;
color: #000000;
margin-bottom: 0;
}
}

.str-chat__message-replies-count-button {
font-family: Helvetica Neue, sans-serif;
font-weight: bold;
font-size: 13px;
text-align: right;
color: #4e1d9d;
}

.str-chat__simple-reactions-list {
border-radius: 10px;
}

.str-chat__reaction-selector {
max-height: 40px;
top: -58px;
right: 20px;
border-radius: 20px;
background: white;
box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.15);
border: 1px solid #bed5e4;
}

.str-chat__message-reactions-list-item__count {
color: #000000;
}

.str-chat__message-simple-status {
right: 22px;
}

.quoted-message-inner {
margin-top: 10px;
box-shadow: 0 2px 6px rgba(0, 0, 0, 0.15);
}

.str-chat__li .quoted-message.mine .quoted-message-inner {
background: #ebebeb;
}

The Result:#

Custom Message UI Component for Chat

Did you find this page helpful?