Info:
This is release candidate documentation for Stream Chat React SDK v15. For the latest stable version, see the latest version (v14).

System message

A system message is a message of type system. It reports an event in the channel rather than something a user wrote, for example a member joining or a moderation command. MessageList and VirtualizedMessageList render it with the MessageSystem override instead of the message UI. This recipe replaces it.

Best practices

  • Keep system messages visually distinct from user messages, but quieter.
  • Show the message's text: it says what happened.
  • Show who triggered the event only where your app's privacy rules allow it. The sender is message.user.
  • Replace MessageSystem for a different layout. For a different look only, style str-chat__message--system.
  • Test with every event your app turns into a system message, such as members being added and removed, and moderation commands.

Default system message component

The default is EventComponent. It renders the message's text in a centered line, or its html when MessageList's unsafeHTML prop is set:

The default system message

A system message comes from the server. Your backend sends one with type: "system", as System messages shows, and adding or removing members can create one, as Channel members shows.

Custom system message component

This component shows the text, the time and the user who triggered the event:

Note:

To see it, mute a user with the /mute command followed by an @mention. The command has to be enabled for the channel type in the Dashboard.

src/CustomSystemMessage.tsx
import type { PropsWithChildren } from "react";
import { convertTimestampToDate } from "stream-chat";
import type { EventComponentProps } from "stream-chat-react";
import { Avatar, WithComponents } from "stream-chat-react";
import "./CustomSystemMessage.css";

const CustomSystemMessage = ({ message }: EventComponentProps) => {
  const { created_at, text, user } = message;
  const date = convertTimestampToDate(created_at);

  return (
    <div className="custom-system-message">
      <div>
        Event: <strong>{text?.trim()}</strong> at {date?.toString()}
      </div>
      {user && (
        <div className="custom-system-message__actor">
          Actor:
          <Avatar
            imageUrl={user.image}
            size="sm"
            userName={user.name || user.id}
          />
          {user.name}
        </div>
      )}
    </div>
  );
};

// Declared once, so WithComponents gets the same object on every render.
const overrides = { MessageSystem: CustomSystemMessage };

export const WithCustomSystemMessages = ({ children }: PropsWithChildren) => (
  <WithComponents overrides={overrides}>{children}</WithComponents>
);

Wrap the channel in it, so every message list inside renders system messages with CustomSystemMessage:

src/ChannelWithSystemMessages.tsx
import type { Channel as StreamChannel } from "stream-chat";
import { Channel, MessageComposer, MessageList } from "stream-chat-react";
import { WithCustomSystemMessages } from "./CustomSystemMessage";

export const ChannelWithSystemMessages = ({
  channel,
}: {
  channel: StreamChannel;
}) => (
  <WithCustomSystemMessages>
    <Channel channel={channel}>
      <MessageList />
      <MessageComposer />
    </Channel>
  </WithCustomSystemMessages>
);
A custom system message with the event, its time and the actor

How it works:

  1. The list renders MessageSystem for every message of type system, and passes the message as message. Unlike a message UI, it renders outside MessageContext, so the message comes from its props.
  2. created_at is a nanosecond number, so convertTimestampToDate turns it into a date; Data conventions explains why.
  3. message.user is the user the server sent the message as. A system message your backend sends without a user has none, so the actor line is left out.

MessageList also passes unsafeHTML. To render a system message's html the way the default does, read that prop as well.

The props are on ComponentContext, under MessageSystem. The other parts of the message list, such as the date separators, are in Message list UI.