# Overriding components

> **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/).

Every replaceable part of the UI has a key in `ComponentsContext`. When an SDK component renders a part, it looks up the part's key and renders your component if you set one, or the SDK's own otherwise. `WithComponents` sets keys for everything below it.

For example, this replaces the date separator between days in every message list, and the send icon everywhere it appears:

```tsx
import type { PropsWithChildren } from "react";
import { StyleSheet, Text, View } from "react-native";
import Svg, { Path } from "react-native-svg";
import type { StreamChat } from "stream-chat";
import {
  Chat,
  OverlayProvider,
  WithComponents,
} from "stream-chat-react-native";
import type {
  ComponentOverrides,
  IconProps,
  InlineDateSeparatorProps,
} from "stream-chat-react-native";

const PlainDateSeparator = ({ date }: InlineDateSeparatorProps) => (
  <View style={styles.separator}>
    <Text>{date?.toLocaleDateString()}</Text>
  </View>
);

const PaperPlaneIcon = ({
  fill,
  height,
  pathFill,
  size,
  stroke,
  width,
  ...rest
}: IconProps) => (
  <Svg
    fill="none"
    height={height ?? size}
    viewBox="0 0 20 20"
    width={width ?? size}
    {...rest}
  >
    <Path
      d="M3 10l14-7-5 14-2-6-7-1z"
      stroke={stroke ?? pathFill ?? fill ?? "black"}
      strokeLinejoin="round"
      strokeWidth={1.5}
    />
  </Svg>
);

// Declared once, at module scope.
const overrides: ComponentOverrides = {
  InlineDateSeparator: PlainDateSeparator,
  icons: { SendRight: PaperPlaneIcon },
};

export const App = ({
  children,
  client,
}: PropsWithChildren<{ client: StreamChat }>) => (
  <WithComponents overrides={overrides}>
    <OverlayProvider>
      <Chat client={client}>{children}</Chat>
    </OverlayProvider>
  </WithComponents>
);

const styles = StyleSheet.create({
  separator: { alignSelf: "center", padding: 4 },
});
```

1. A message list renders a date separator above the first message of each day. It reads the `InlineDateSeparator` key and finds `PlainDateSeparator`, which receives the day as `date`.
2. The send button reads its icon from the `icons` key and finds `PaperPlaneIcon` under `SendRight`.
3. Every other key keeps the SDK's component.

## How overrides merge

`WithComponents` takes one prop, `overrides`, an object of type `ComponentOverrides`. Every key is optional.

- **Nested providers merge.** The keys in `overrides` replace the same keys from any `WithComponents` above it, and every other key keeps its outer value. The closest provider wins.
- **`icons` merges icon by icon.** Overriding one icon keeps the icons an outer provider set, and the SDK's defaults for the rest.
- **There is nothing to reset with.** No provider drops the overrides from above. To give a part of the app the SDK's own component back, set the key to the default component again, for example `{ InlineDateSeparator }` imported from `stream-chat-react-native`.

Nesting scopes an override to part of the app:

```tsx
import { Text } from "react-native";
import type { Channel as StreamChannel } from "stream-chat";
import {
  Channel,
  MessageComposer,
  MessageList,
  WithComponents,
} from "stream-chat-react-native";
import type {
  ComponentOverrides,
  InlineDateSeparatorProps,
} from "stream-chat-react-native";

const DayOnly = ({ date }: InlineDateSeparatorProps) => (
  <Text>{date?.toLocaleDateString()}</Text>
);

const RepliesClosed = () => <Text>Replies are closed.</Text>;

const appOverrides: ComponentOverrides = { InlineDateSeparator: DayOnly };
const supportOverrides: ComponentOverrides = {
  SendMessageDisallowedIndicator: RepliesClosed,
};

export const SupportChannel = ({ channel }: { channel: StreamChannel }) => (
  <WithComponents overrides={appOverrides}>
    {/* This channel keeps DayOnly and replaces the notice too. */}
    <WithComponents overrides={supportOverrides}>
      <Channel channel={channel}>
        <MessageList />
        <MessageComposer />
      </Channel>
    </WithComponents>
  </WithComponents>
);
```

### Overrides are read once

`WithComponents` builds its merged value when it mounts and keeps it. A new `overrides` object passed on a later render is ignored, and so is a change in an outer provider. `useComponentsContext()` also reads the context once per component. So:

- **Declare `overrides` at module scope,** as above, with components declared at module scope too.
- **Don't make an override depend on state.** A component you set can read state and context like any other, so put the logic inside the component rather than choosing a different component on each render.
- **To switch overrides while the app runs, remount the subtree,** for example by giving the `WithComponents` a `key` that changes. Everything below it mounts again and reads the new value.

### Where to put WithComponents

A key takes effect only from a `WithComponents` above the component that reads it. Most keys are read inside `Channel`, `Thread`, `ChannelList`, `ThreadList` or `ChannelDetails`, so a provider around those is enough. A few are read higher up:

| Keys                                                                                                                                      | Read by           |
| ----------------------------------------------------------------------------------------------------------------------------------------- | ----------------- |
| `ChatLoadingIndicator`                                                                                                                    | `Chat`            |
| `ImageGalleryHeader`, `ImageGalleryFooter`, `ImageGalleryGrid`, `ImageGalleryVideoControls`, `MessageOverlayBackground`, `MessageActions` | `OverlayProvider` |

For app-wide overrides, put `WithComponents` around `OverlayProvider`, as the first example does. The image gallery also renders icons, so icon overrides set below `OverlayProvider` don't reach it.

## Reading slots in your own components

`useComponentsContext()` returns every key, with the overrides in effect merged over the defaults. Every key with a default is defined, so you can render it without a check:

```tsx
import { Pressable } from "react-native";
import { useComponentsContext, useTheme } from "stream-chat-react-native";

export const SearchButton = ({ onPress }: { onPress: () => void }) => {
  const { icons } = useComponentsContext();
  const {
    theme: { semantics },
  } = useTheme();

  return (
    <Pressable accessibilityLabel="Search" onPress={onPress}>
      <icons.Search height={20} stroke={semantics.textPrimary} width={20} />
    </Pressable>
  );
};
```

A custom component that renders a part through `useComponentsContext()` shows the app's override of that part, the same way the SDK's components do.

The keys in the [optional slots](#optional-slots) have no default and are `undefined` until you set them.

## Override keys by area

The table groups every key by the part of the screen it renders, and links to the page that covers that part. The defaults are declared in `package/src/contexts/componentsContext/defaultComponents.ts` in the SDK's repository, and the `ComponentOverrides` type lists every key with its props in your editor. [ComponentsContext](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/channel/componentscontext/) covers `WithComponents`, `useComponentsContext()` and their types.

| Area                                                                                                          | Keys                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| ------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------ |
| [Message list](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/#replacing-parts)                | `DateHeader`, `EmptyStateIndicator`, `InlineDateSeparator`, `InlineUnreadIndicator`, `LoadingErrorIndicator`, `MessageListLoadingIndicator`, `MessageSystem`, `NetworkDownIndicator`, `ScrollToBottomButton`, `StickyHeader`, `TypingIndicator`, `TypingIndicatorContainer`, `UnreadMessagesNotification`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                  |
| [A message](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-list-ui/#replacing-parts)                   | `Message`, `MessageItemView`, `MessageAuthor`, `MessageBlocked`, `MessageBounce`, `MessageContent`, `MessageDeleted`, `MessageError`, `MessageFooter`, `MessageHeader`, `MessagePinnedHeader`, `MessageReminderHeader`, `MessageReplies`, `MessageRepliesAvatars`, `MessageSavedForLaterHeader`, `MessageStatus`, `MessageSwipeContent`, `MessageTimestamp`, `Reply`, `SentToChannelHeader`, `StreamingMessageView`                                                                                                                                                                                                                                                                                                                                                                        |
| [Reactions](https://getstream.io/chat/docs/sdk/react-native/v10/features/messaging/reactions/)                                    | `MessageReactionPicker`, `MessageUserReactions`, `MessageUserReactionsAvatar`, `MessageUserReactionsItem`, `ReactionListBottom`, `ReactionListClustered`, `ReactionListCountItem`, `ReactionListItem`, `ReactionListTop`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| [Message menu](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overlays-and-bottom-sheets/)                    | `MessageActionList`, `MessageActionListItem`, `MessageOverlayBackground`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                   |
| [Attachments](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/attachments-and-uploads/)                 | `Attachment`, `AttachmentUploadIndicator`, `AudioAttachment`, `CircularProgressIndicator`, `FileAttachment`, `FileAttachmentGroup`, `FileAttachmentIcon`, `FilePreview`, `Gallery`, `Giphy`, `ImageComponent`, `ImageLoadingFailedIndicator`, `ImageLoadingIndicator`, `MediaUploadProgressOverlay`, `UnsupportedAttachment`, `UrlPreview`, `URLPreviewCompact`, `VideoThumbnail`                                                                                                                                                                                                                                                                                                                                                                                                          |
| [Image gallery](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overlays-and-bottom-sheets/)                   | `ImageGalleryFooter`, `ImageGalleryGrid`, `ImageGalleryHeader`, `ImageGalleryVideoControls`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                |
| [Message composer](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/message-composer-ui/#replacing-parts)        | `AttachButton`, `AttachmentUploadPreviewList`, `AudioAttachmentUploadPreview`, `AutoCompleteSuggestionHeader`, `AutoCompleteSuggestionItem`, `AutoCompleteSuggestionList`, `CooldownTimer`, `FileAttachmentUploadPreview`, `FileUploadInProgressIndicator`, `FileUploadNotSupportedIndicator`, `FileUploadRetryIndicator`, `ImageAttachmentUploadPreview`, `ImageUploadInProgressIndicator`, `ImageUploadNotSupportedIndicator`, `ImageUploadRetryIndicator`, `InputView`, `KeyboardCompatibleView`, `MentionSuggestionItem`, `MessageComposerLeadingView`, `MessageComposerTrailingView`, `MessageInputHeaderView`, `MessageInputTrailingView`, `SendButton`, `SendMessageDisallowedIndicator`, `StartAudioRecordingButton`, `StopMessageStreamingButton`, `VideoAttachmentUploadPreview` |
| [Voice recording](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/voice-recordings-and-audio-playback/) | `AudioRecorder`, `AudioRecordingInProgress`, `AudioRecordingLockIndicator`, `AudioRecordingPreview`, `AudioRecordingWaveform`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                              |
| [Attachment picker](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overlays-and-bottom-sheets/)               | `AttachmentPickerContent`, `AttachmentPickerSelectionBar`, `ImageOverlaySelectedComponent`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                 |
| [Polls](https://getstream.io/chat/docs/sdk/react-native/v10/features/rich-content/polls/)                                         | `PollAllOptionsContent`, `PollAnswersListContent`, `PollButtons`, `PollHeader`, `PollOptionFullResultsContent`, `PollResultsContent`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                       |
| [Channel list](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/channel-list-ui/#replacing-parts)                | `ChannelDetailsBottomSheet`, `ChannelDetailsHeader`, `ChannelListFooterLoadingIndicator`, `ChannelListHeaderErrorIndicator`, `ChannelListHeaderNetworkDownIndicator`, `ChannelListLoadingIndicator`, `ChannelPreview`, `ChannelPreviewAvatar`, `ChannelPreviewLastMessage`, `ChannelPreviewMessage`, `ChannelPreviewMessageDeliveryStatus`, `ChannelPreviewMutedStatus`, `ChannelPreviewPinnedStatus`, `ChannelPreviewStatus`, `ChannelPreviewTitle`, `ChannelPreviewTypingIndicator`, `ChannelPreviewUnreadCount`, `Skeleton`                                                                                                                                                                                                                                                             |
| [Channel details](https://getstream.io/chat/docs/sdk/react-native/v10/features/channels/channel-details-and-members/)             | `ChannelAddMembersButton`, `ChannelAddMembersForm`, `ChannelAddMembersFormContent`, `ChannelAddMembersFormHeader`, `ChannelDetailsActionItem`, `ChannelDetailsActionsSection`, `ChannelDetailsContent`, `ChannelDetailsEditButton`, `ChannelDetailsMemberSection`, `ChannelDetailsNavHeader`, `ChannelDetailsNavigationSection`, `ChannelDetailsProfile`, `ChannelEditDetailsForm`, `ChannelEditDetailsFormContent`, `ChannelEditDetailsFormHeader`, `ChannelEditImageSheet`, `ChannelEditName`, `ChannelMemberActionsSheet`, `ChannelMemberItem`, `ChannelMemberList`, `FileAttachmentItem`, `FileAttachmentList`, `MediaItem`, `MediaList`, `PinnedMessageItem`, `PinnedMessageList`, `RoleItem`, `RoleList`                                                                             |
| [Thread list](https://getstream.io/chat/docs/sdk/react-native/v10/ui/components/thread-ui/#replacing-parts)                       | `ThreadListComponent`, `ThreadListEmptyPlaceholder`, `ThreadListItem`, `ThreadListItemMessagePreview`, `ThreadListLoadingIndicator`, `ThreadListLoadingMoreIndicator`, `ThreadListUnreadBanner`, `ThreadMessagePreviewDeliveryStatus`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                      |
| [Notifications](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/displaying-notifications/)                     | `Notification`, `NotificationIcon`, `NotificationList`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                     |
| [Icons](#icons)                                                                                               | `icons`                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                                    |

`EmptyStateIndicator` and `LoadingErrorIndicator` are shared: the channel list renders them too, and `Channel` and `Thread` render `LoadingErrorIndicator` when their first page fails to load. `ImageComponent` renders the images of attachments, previews and channel details, so a replacement can add caching or a different image library.

### Optional slots

These keys have no default. The SDK renders nothing for them, or its built-in part, until you set one:

| Key                                                                                                            | Where it renders                                                                                                                                                          |
| -------------------------------------------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `ChatLoadingIndicator`                                                                                         | in place of `Chat`'s children while the offline database opens                                                                                                            |
| `ListHeaderComponent`                                                                                          | above the channel list                                                                                                                                                    |
| `MessageContentTopView`, `MessageContentBottomView`, `MessageContentLeadingView`, `MessageContentTrailingView` | around a message's content, inside its bubble                                                                                                                             |
| `MessageSpacer`                                                                                                | last in each message row, outside the bubble                                                                                                                              |
| `MessageText`                                                                                                  | in place of the default rendering of a message's text                                                                                                                     |
| `MessageLocation`                                                                                              | a location shared in a message, which renders nothing without this key                                                                                                    |
| `Input`                                                                                                        | in place of the composer's whole row: input, buttons and previews                                                                                                         |
| `PollContent`                                                                                                  | in place of the default content of a poll in a message                                                                                                                    |
| `CreatePollContent`                                                                                            | in place of the default content of the poll creation screen                                                                                                               |
| `MessageActions`                                                                                               | in place of the layout of the message menu, see [Overlays and bottom sheets](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/overlays-and-bottom-sheets/#the-message-menu) |

### Keys that change nothing

The `ComponentOverrides` type also lists `AttachmentPickerIOSSelectMorePhotos`, `InputButtons`, `MessageInputFooterView`, `MessageInputLeadingView`, `ReactionListItemWrapper` and `ShowThreadMessageInChannelButton`, but no component reads them, so setting them has no effect. To change the composer's input buttons, override `MessageComposerLeadingView`, which renders them. `MessageList` has no key because you render it yourself: see [Composition](#composition).

## Icons

Every icon the SDK renders, from the send arrow and the delivery checkmarks to the mute and pin badges and the attachment picker's glyphs, comes from the `icons` key. Give it only the icons you want to change: the others keep their defaults.

```tsx
import Svg, { Path } from "react-native-svg";
import type { ChannelPaginator } from "stream-chat";
import { ChannelList, WithComponents } from "stream-chat-react-native";
import type { ComponentOverrides, IconProps } from "stream-chat-react-native";

const SlashedBellIcon = ({
  fill,
  height,
  pathFill,
  size,
  stroke,
  width,
  ...rest
}: IconProps) => (
  <Svg
    fill="none"
    height={height ?? size}
    viewBox="0 0 20 20"
    width={width ?? size}
    {...rest}
  >
    <Path
      d="M4 4l12 12M8 16h4M6 8a4 4 0 017.5-2M14 10v2l1.5 2H7"
      stroke={stroke ?? pathFill ?? fill ?? "black"}
      strokeLinecap="round"
      strokeWidth={1.5}
    />
  </Svg>
);

const iconOverrides: ComponentOverrides = {
  icons: { Mute: SlashedBellIcon },
};

export const ChannelListWithIcons = ({
  paginator,
}: {
  paginator: ChannelPaginator;
}) => (
  <WithComponents overrides={iconOverrides}>
    <ChannelList paginator={paginator} />
  </WithComponents>
);
```

The mute icon in that subtree, for example on a muted channel's row and in its actions sheet, is now `SlashedBellIcon`. The names are those of the icon components `stream-chat-react-native` exports, such as `SendRight`, `ThreadReply`, `Pin`, `Mute` and `Search`, and `ComponentOverrides["icons"]` lists every one. The icon of a file attachment is a separate key, `FileAttachmentIcon`.

### What an icon receives

An icon is a component that takes `IconProps`: the props of `react-native-svg`'s `Svg`, plus `size`, `pathFill` and `pathOpacity`.

- **Size.** The SDK passes `width` and `height`, or `size`. Use them, so the icon fits the place it renders in.
- **Color.** The SDK passes the color from the theme as `stroke`, `fill` or `pathFill`, depending on the icon: an outlined glyph usually gets `stroke`, a filled one `fill` or `pathFill`. Read whichever your icon draws with, falling back to the others, as `SlashedBellIcon` does, and the icon follows the theme and states such as disabled.
- **The rest,** such as `strokeWidth` from a button, can be spread on the `Svg`.

### Any component as an icon

An icon doesn't have to be an SVG. An image, or an icon from another library, works as long as it takes `IconProps`:

```tsx
import { Image } from "react-native";
import type { IconProps } from "stream-chat-react-native";

export const LogoSendIcon = ({ height, size, width }: IconProps) => (
  <Image
    source={{ uri: "https://example.com/logo-send.png" }}
    style={{ height: height ?? size ?? 20, width: width ?? size ?? 20 }}
  />
);
```

Keep icons light: one may render once per message row.

### Inheritance

Icon overrides merge icon by icon across nested `WithComponents`. Set app-wide icons around `OverlayProvider`, and override one icon deeper down where a part of the app needs it:

```tsx
import Svg, { Circle, Rect } from "react-native-svg";
import type { Channel as StreamChannel, StreamChat } from "stream-chat";
import {
  Channel,
  Chat,
  MessageComposer,
  MessageList,
  OverlayProvider,
  WithComponents,
} from "stream-chat-react-native";
import type { ComponentOverrides, IconProps } from "stream-chat-react-native";

const BrandSendIcon = ({ height, size, stroke, width }: IconProps) => (
  <Svg height={height ?? size} viewBox="0 0 20 20" width={width ?? size}>
    <Circle cx={10} cy={10} fill={stroke ?? "black"} r={7} />
  </Svg>
);

const UrgentSendIcon = ({ height, size, stroke, width }: IconProps) => (
  <Svg height={height ?? size} viewBox="0 0 20 20" width={width ?? size}>
    <Rect fill={stroke ?? "black"} height={14} width={14} x={3} y={3} />
  </Svg>
);

const brandIcons: ComponentOverrides = { icons: { SendRight: BrandSendIcon } };
const urgentIcons: ComponentOverrides = {
  icons: { SendRight: UrgentSendIcon },
};

export const App = ({
  client,
  escalations,
}: {
  client: StreamChat;
  escalations: StreamChannel;
}) => (
  <WithComponents overrides={brandIcons}>
    <OverlayProvider>
      <Chat client={client}>
        {/* This channel uses UrgentSendIcon; every other icon is inherited. */}
        <WithComponents overrides={urgentIcons}>
          <Channel channel={escalations}>
            <MessageList />
            <MessageComposer />
          </Channel>
        </WithComponents>
      </Chat>
    </OverlayProvider>
  </WithComponents>
);
```

Many icon colors and sizes can be changed through the [theme](https://getstream.io/chat/docs/sdk/react-native/v10/ui/customizing/theming/) without replacing the icon. Replace the icon when its shape has to change.

## Composing from the default component

The SDK's components are exported, so an override can render the default with different props, or wrap it. `ChannelPreviewTitle`, for example, takes the channel and an optional `title`:

```tsx
import {
  ChannelPreviewTitle,
  useChannelPreviewDisplayName,
  useIsDirectChat,
} from "stream-chat-react-native";
import type {
  ChannelPreviewTitleProps,
  ComponentOverrides,
} from "stream-chat-react-native";

const HashTitle = (props: ChannelPreviewTitleProps) => {
  const displayName = useChannelPreviewDisplayName(props.channel);
  const isDirectChat = useIsDirectChat(props.channel);

  return (
    <ChannelPreviewTitle
      {...props}
      title={isDirectChat ? displayName : `# ${displayName}`}
    />
  );
};

export const titleOverrides: ComponentOverrides = {
  ChannelPreviewTitle: HashTitle,
};
```

Forward the props you receive, and change only what you need: the default keeps its styling, its theme keys and the parts it reads from context.

### A custom MessageItemView

`Message` holds the logic of each message in a list, and renders its look through the `MessageItemView` key. The SDK passes `MessageItemView` **no props**. `Message` puts everything about the message into `MessageContext`, and the component reads it with `useMessageContext()`. The parts the default is built from read the same context, so a custom one can compose them:

```tsx
import { Pressable, StyleSheet, Text } from "react-native";
import {
  MessageContent,
  MessageFooter,
  useMessageContext,
} from "stream-chat-react-native";
import type { ComponentOverrides } from "stream-chat-react-native";

const CompactMessage = () => {
  const { isMyMessage, message, onLongPress } = useMessageContext();

  if (message.type === "deleted") {
    return <Text style={styles.deleted}>Message deleted</Text>;
  }

  return (
    <Pressable
      onLongPress={(event) => onLongPress({ emitter: "message", event })}
      style={[styles.row, isMyMessage && styles.mine]}
    >
      <Text style={styles.author}>
        {message.user?.name ?? message.user?.id}
      </Text>
      <MessageContent />
      <MessageFooter />
    </Pressable>
  );
};

export const messageOverrides: ComponentOverrides = {
  MessageItemView: CompactMessage,
};

const styles = StyleSheet.create({
  author: { fontWeight: "600" },
  deleted: { fontStyle: "italic", padding: 8 },
  mine: { alignSelf: "flex-end" },
  row: { maxWidth: "80%", padding: 8 },
});
```

`MessageItemView` renders every regular message: deleted ones, failed ones, ones with a poll or a quoted message. The default handles all of them. A custom one handles the cases your app has. System messages go to `MessageSystem` instead, and blocked messages to `MessageBlocked`.

The message menu opens through `onLongPress` from `MessageContext`. `MessageContent` already calls it on a long press of the bubble, and the `Pressable` above adds the rest of the row. A custom component that doesn't render `MessageContent` has to call it itself, or the menu never opens.

Keep a custom message light: it renders once per row of the list. Read what it needs from `useMessageContext()`, and avoid subscribing each row to state that changes for the whole list, such as the paginator's `state.items`: a change there re-renders every row. The message parts and their props are on [Message UI components](https://getstream.io/chat/docs/sdk/react-native/v10/component-reference/message/message-ui-components/), and a full walkthrough is the [Custom message](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/message/custom-message/) UI cookbook.

## Composition

Not every change needs a key. `Channel` and `Thread` render no list or composer of their own. Besides the keyboard-avoiding view around their children and the attachment picker, they render only the children you give them, so their content is yours to compose: leave a part out, add your own, or change the order.

```tsx
import { StyleSheet, Text, View } from "react-native";
import type { Channel as StreamChannel } from "stream-chat";
import {
  Channel,
  MessageComposer,
  MessageList,
} from "stream-chat-react-native";

const RulesBanner = () => (
  <View style={styles.banner}>
    <Text>Be kind. Moderators are watching.</Text>
  </View>
);

export const ModeratedChannel = ({ channel }: { channel: StreamChannel }) => (
  <Channel channel={channel}>
    <RulesBanner />
    <MessageList />
    <MessageComposer />
  </Channel>
);

const styles = StyleSheet.create({
  banner: { padding: 8 },
});
```

The SDK has no channel header or thread header component: the screen's header belongs to your navigation. See [Navigation](https://getstream.io/chat/docs/sdk/react-native/v10/ui/layout/navigation/), and the [Channel header](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/headers/channel-header/) UI cookbook for a header that shows the channel's name, avatar and typing state.

## Pitfalls

- **An `overrides` object that changes.** `WithComponents` reads `overrides` once, when it mounts. A later object, or an override chosen from state, is ignored. Declare overrides at module scope, and put changing logic inside the component.
- **An override below the component that reads it.** The image gallery and the message menu's background are rendered by `OverlayProvider`, and the loading indicator by `Chat`. Overrides for them, and icon overrides meant for the gallery, go above `OverlayProvider`.
- **A custom `MessageItemView` that expects props.** It receives none: read `useMessageContext()`.
- **A custom message that never calls `onLongPress`.** Without `MessageContent`, or your own call to `onLongPress` from `MessageContext`, the message menu doesn't open.
- **An icon that ignores the props it gets.** A hard-coded size or color doesn't follow the theme or the disabled state. Read `width`, `height`, `size`, `stroke`, `fill` and `pathFill`.
- **A key from the [list of keys that change nothing](#keys-that-change-nothing).** Override the component that renders the part instead.

Used in: most Features pages and every UI cookbook, for example [Custom message](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/message/custom-message/) and [Custom composer](https://getstream.io/chat/docs/sdk/react-native/v10/ui-cookbook/composer/custom-composer/).

---

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