# Overview

The core of Stream Chat React Native is its flexibility. Many apps only need [the theme](/chat/docs/sdk/react-native/v8/customization/theming/). For deeper changes or new behavior, build a custom component.

## Best Practices

- Start with theming; only create custom components when behavior/layout must change.
- Replace components via `Channel` props to keep integration consistent.
- Return `null` to remove UI features cleanly.
- Use the right context for your component’s scope; avoid message-level re-renders.
- Keep custom components lightweight, especially inside `MessageList`.

## When to use a custom component

Build a custom component when you need to insert custom UI, significantly change layout, or modify behavior. With few exceptions, what you see is what you get.

### Exceptions

- Padding, fonts, colors, borders, etc. can all be altered from [the theme](/chat/docs/sdk/react-native/v8/customization/theming/) as styles are passed to most components and sub-components.
- Messages can be aligned to one side using the `forceAlignMessages` prop on the `Channel` component.
- Message content can be reordered using the `messageContentOrder` prop on `Channel`; but you may want to adjust the theming to account for changes to border alignments if you alter this order.

Changes beyond these tweaks require custom components. To remove a UI feature, replace it with a component that returns `null`.

## How to use a custom component

Most custom components are passed as props on `Channel` (with a few exceptions on `OverlayProvider`, `MessageList`, and `ChannelList`).

To remove the fixed `DateHeader`, pass `undefined`:

```tsx

<Channel
  ...
  DateHeader={undefined}
>
```

Your custom component replaces the default everywhere it is used. Most components read from context; some also receive props. `DateHeader` receives a `dateString` prop.

```tsx
const MyNewComponent = ({ dateString }) => <Text>{`Hello World: ${dateString}`}</Text>;

<Channel
  ...
  DateHeader={MyNewComponent}
>
```

![DateHeader](@chat-sdk/react-native/v8/_assets/customization/custom-components/date_header.png)

![NoDateHeader](@chat-sdk/react-native/v8/_assets/customization/custom-components/no_date_header.png)

![NewDateHeader](@chat-sdk/react-native/v8/_assets/customization/custom-components/new_date_header.png)

## Using contexts

Custom components typically read from SDK contexts. Use [the hooks](/chat/docs/sdk/react-native/v8/customization/contexts#hooks/) within their provider scope. Some contexts, like `MessageContext`, are only available inside a `Message`, so you can't use them in `DateHeader`.

Example: replace `DateHeader` with a component that reads `PaginatedMessageListContext` and displays the last sender.

```tsx
const MySenderComponent = () => {
  const { messages } = usePaginatedMessageListContext();
  const latestMessageSender = messages[messages.length - 1]?.user?.name;

  return <Text>{`Last Sender: ${latestMessageSender}`}</Text>;
};

<Channel
  ...
  DateHeader={MySenderComponent}
>
```

![NameDateHeader](@chat-sdk/react-native/v8/_assets/customization/custom-components/name_date_header.png)

This lets you tailor both UI and the information you show.

<admonition type="warning">

Custom components within a `Message` should draw from mostly static contexts, except their own `MessageContext`. `ThemeContext`, `MessagesContext`, and `TranslationContext` are safe in most cases.

Memoizing values from contexts above the [`FlatList`](https://reactnative.dev/docs/flatlist) inside a row does not work well when those contexts update. Reading `PaginatedMessageListContext` inside each `Message` will cause the whole list to re-render.

</admonition>

## Common customization patterns

Here are some frequently requested customization examples:

### Custom message bubble

Replace the default message appearance with a custom design:

```tsx
import { View, Text, StyleSheet } from "react-native";
import { Channel, useMessageContext } from "stream-chat-react-native";

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

  return (
    <View
      style={[
        styles.messageContainer,
        isMyMessage ? styles.myMessage : styles.theirMessage,
      ]}
    >
      {!isMyMessage && (
        <Text style={styles.username}>{message.user?.name}</Text>
      )}
      <Text style={styles.messageText}>{message.text}</Text>
    </View>
  );
};

const styles = StyleSheet.create({
  messageContainer: {
    padding: 12,
    borderRadius: 16,
    maxWidth: "80%",
    marginVertical: 4,
  },
  myMessage: {
    backgroundColor: "#007AFF",
    alignSelf: "flex-end",
  },
  theirMessage: {
    backgroundColor: "#E5E5EA",
    alignSelf: "flex-start",
  },
  username: {
    fontSize: 12,
    color: "#666",
    marginBottom: 4,
  },
  messageText: {
    fontSize: 16,
  },
});

// Usage
<Channel MessageContent={CustomMessageContent} />;
```

### Custom send button

Create a send button with custom styling or behavior:

```tsx
import { TouchableOpacity, StyleSheet } from "react-native";
import { useMessageInputContext, SendIcon } from "stream-chat-react-native";

const CustomSendButton = () => {
  const { sendMessage } = useMessageInputContext();

  return (
    <TouchableOpacity style={styles.sendButton} onPress={sendMessage}>
      <SendIcon />
    </TouchableOpacity>
  );
};

const styles = StyleSheet.create({
  sendButton: {
    backgroundColor: "#007AFF",
    borderRadius: 20,
    padding: 8,
    marginLeft: 8,
  },
});

// Usage
<Channel SendButton={CustomSendButton} />;
```

### Remove a UI element

To completely remove a UI element, pass a component that returns `null`:

```tsx
// Remove the typing indicator
<Channel TypingIndicator={() => null} />;

// Remove the date header
<Channel DateHeader={undefined} />;

// Remove message avatars
<Channel MessageAvatar={() => null} />;
```


---

This page was last updated at 2026-04-17T17:33:45.159Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/react-native/v8/customization/custom_components/](https://getstream.io/chat/docs/sdk/react-native/v8/customization/custom_components/).