# System message

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

A system message is a message of type `system`. It reports something that happened in the channel rather than something a user wrote, for example members being added. `MessageList` and `MessageFlashList` render it with the `MessageSystem` key in place of `Message`. This UI cookbook restyles the default system message, then replaces it. Where it sits among the list's other parts is explained in [Message list UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/#a-message).

## Best practices

- Keep system messages visually distinct from user messages, but quieter.
- Show the message's text, which says what happened.
- Show who triggered the event only where your app's privacy rules allow it. The sender is `message.user`.
- Restyle the default through the theme when only its look changes, and replace `MessageSystem` for a different layout.
- Read the message from the component's props. `MessageSystem` renders outside `MessageContext`.
- Test with every event your app turns into a system message, such as members being added and removed.

## The default system message

`MessageSystem` renders the message's `text` and its time side by side, in a box with a border and rounded corners. The time comes from the `timestamp.MessageSystem` translation key, a calendar date like the date separators' one; [Changing a format](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/localization/#changing-a-format) shows how to change it.

A system message comes from the server. Your backend sends one with `type: "system"`, as [System messages](https://getstream.io/chat/docs/javascript/silent-messages/#system-messages) shows, and `Channel.addMembers()`, `Channel.removeMembers()` and `Channel.inviteMembers()` take a `message` to send with the change, as [Channel members](https://getstream.io/chat/docs/javascript/channel-members/#system-message-parameter) shows.

The list treats a system message differently from other messages:

- It gets no date separator, unless `allowDateSeparatorForSystemMessages` is set on `Channel` or `Thread`. [Date separators](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/message/date-separators/#when-a-separator-shows) explains the rule.
- It breaks the grouping of messages. The message above it ends a group, and the message below it starts a new one.
- It has no message menu, reactions or swipe to reply, because it doesn't render `Message`.
- `myMessageTheme` doesn't apply to it, even when the current user sent it.

### Restyling the default

`MessageSystem` styles its box with `messageItemView.messageBlocked.container` and both texts with `messageItemView.messageBlocked.text`, and adds `messageList.messageSystem.dateText` to the time. `MessageBlocked`, which renders a message blocked by moderation, reads the same two `messageBlocked` keys, so a change to them restyles both:

```ts
import type { DeepPartial, Theme } from "stream-chat-react-native";

export const theme: DeepPartial<Theme> = {
  messageItemView: {
    messageBlocked: {
      container: { borderRadius: 4, borderWidth: 0 },
      text: { fontStyle: "italic" },
    },
  },
  messageList: {
    messageSystem: { dateText: { fontWeight: "600" } },
  },
};
```

The colors come from the semantic tokens `chatTextSystem` for the text, `backgroundCoreSurfaceSubtle` for the background and `borderCoreSubtle` for the border. Other components read them too: `chatTextSystem`, for example, also colors the date separators and the unread separator. The list passes `messageList.messageContainer` as the component's `style`, and the same style wraps every other message. The other keys under `messageList.messageSystem`, `container`, `line`, `text` and `textContainer`, and `messageList.systemMessageContainer`, aren't read by any component.

## A custom system message

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

```tsx title="src/CustomSystemMessage.tsx"
import { useMemo } from "react";
import { StyleSheet, Text, View } from "react-native";
import { convertTimestampToDate } from "stream-chat";
import {
  getDateString,
  UserAvatar,
  useTheme,
  useTranslationContext,
} from "stream-chat-react-native";
import type {
  ComponentOverrides,
  MessageSystemProps,
} from "stream-chat-react-native";

const CustomSystemMessage = ({ message, style }: MessageSystemProps) => {
  const { created_at, text, user } = message;
  const { t, tDateTimeParser } = useTranslationContext();
  const {
    theme: { semantics },
  } = useTheme();

  const time = useMemo(
    () =>
      getDateString({
        messageCreatedAt: convertTimestampToDate(created_at),
        t,
        tDateTimeParser,
        timestampTranslationKey: "timestamp.MessageSystem",
      }),
    [created_at, t, tDateTimeParser],
  );

  return (
    <View style={[styles.row, style]}>
      <View
        style={[
          styles.card,
          {
            backgroundColor: semantics.backgroundCoreSurfaceSubtle,
            borderColor: semantics.accentPrimary,
          },
        ]}
      >
        <Text style={[styles.text, { color: semantics.textPrimary }]}>
          {text?.trim()}
        </Text>
        {time ? (
          <Text style={[styles.meta, { color: semantics.textSecondary }]}>
            {time}
          </Text>
        ) : null}
        {user ? (
          <View style={styles.actor}>
            <UserAvatar size="xs" user={user} />
            <Text style={[styles.meta, { color: semantics.textSecondary }]}>
              {user.name || user.id}
            </Text>
          </View>
        ) : null}
      </View>
    </View>
  );
};

export const systemMessageOverrides: ComponentOverrides = {
  MessageSystem: CustomSystemMessage,
};

const styles = StyleSheet.create({
  actor: { alignItems: "center", flexDirection: "row", gap: 6 },
  card: {
    alignItems: "center",
    borderLeftWidth: 3,
    borderRadius: 8,
    gap: 4,
    maxWidth: 320,
    paddingHorizontal: 12,
    paddingVertical: 8,
  },
  meta: { fontSize: 12 },
  row: { alignItems: "center", paddingHorizontal: 16, paddingVertical: 4 },
  text: { fontSize: 13, fontWeight: "600", textAlign: "center" },
});
```

<table>
  <tr>
  <td align='center' width='50%'>

![A system message shown as a card with the text, the time and the user who triggered it on iOS](https://getstream.io/docs-assets/images/3030f73e5a9f.png)

  </td>
  <td align='center' width='50%'>

![A system message shown as a card with the text, the time and the user who triggered it on Android](https://getstream.io/docs-assets/images/d709a8c08f8d.png)

  </td>
  </tr>
</table>

Pass `systemMessageOverrides` to a `WithComponents` around `Channel` and `Thread`, so every message list inside renders system messages with `CustomSystemMessage`. How it works:

1. The list renders the `MessageSystem` key for every message whose `type` is `system`, and passes the message as `message` and the `messageList.messageContainer` theme style as `style`. It renders outside `MessageContext`, so `useMessageContext()` has no message there, and the message comes from the props.
2. `created_at` is a nanosecond number, so `convertTimestampToDate()` turns it into a date; [Data conventions](https://getstream.io/chat/docs/sdk/react-native/v10/state/state-and-entities/data-conventions/#timestamps) explains why. `getDateString()` formats it with the same translation key as the default, so a format registered for `timestamp.MessageSystem` applies to both.
3. `message.user` is the user the server sent the message as. `UserAvatar` renders their image, and falls back to their initials, or an icon for a user without a name. When the message has no user, the actor row is left out.

The text renders as plain text, without Markdown or mentions. The other parts of the message list, such as the date separators, are listed in [Message list UI](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/#replacing-parts).

## Read more

- [Message UI components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/message-ui-components/#messagesystem): the props of `MessageSystem`.
- [Date separators](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/message/date-separators/): separators above system messages, and days that hold nothing but system messages.
- [Avatars](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/base-ui/avatars/): `UserAvatar` and its sizes.
- [Theme object](https://getstream.io/chat/docs/sdk/react-native/v10/reference/theme/theme-object/): every theme key, those of `messageList` and `messageItemView` included.

---

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/message/system-message/](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/message/system-message/).