# Component Factory

The `ChatComponentFactory` is a factory which defines most of the stateless
low-level composable components, which are used as building blocks for the
high-level screen components and the bound components
(see [Component Architecture](/chat/docs/sdk/android/compose/component-architecture/)).

The screen components, the bound components, and even the low-level components
which depend on different low-level components, use the `ChatComponentFactory`
to render specific components of the UI in a stateless manner.

By overriding the `ChatComponentFactory`, developers can easily customize or
override specific parts of the Chat UI, without the need to build their own
implementations from scratch. This enables a high degree of customization and
flexibility, allowing the Chat UI to be tailored to specific design requirements.

<admonition type="note">

The <b>ChatComponentFactory</b> is available on the Compose SDK since version <b><a href="https://github.com/GetStream/stream-chat-android/releases/tag/v6.11.0">6.11.0</a></b>

</admonition>

## Usage

To apply a custom component factory to your Chat UI, all you need to do is to
implement the `ChatComponentFactory` interface:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    // Override the specific composable methods which you like to customize
}
```

And pass the custom `ChatComponentFactory` to the `ChatTheme` wrapping your
Chat UI:

```kotlin
ChatTheme(
    componentFactory = CustomChatComponentFactory(),
) {
    MessagesScreen(
        viewModelFactory = viewModelFactory,
    )
}
```

The custom components provided by the custom `ChatComponentFactory` will now
override all the default components used by the wrapped `MessagesScreen`.

## Customization options

The `ChatComponentFactory` allows customization of most low-level components
used in different Chat screens. It provides the ability to customize common components globally,
as well as specific components in particular locations.

### Available Components

| Component                | Description                                                      |
| ------------------------ | ---------------------------------------------------------------- |
| **Avatars**              | Customize user, group, and channel avatars.                      |
| **Channel List Header**  | Modify the header of the channel list.                           |
| **Channel Items**        | Customize how individual channels and their elements appear.     |
| **Messages List Header** | Customize the header of the message list.                        |
| **Messages Items**       | Customize message bubbles, timestamps, and other elements.       |
| **Message Composer**     | Customize the message input field, send button, and attachments. |
| **Menus & Actions**      | Customize context menus for messages and channels.               |
| **Reactions**            | Modify the reaction picker and displayed reactions.              |
| **Thread List**          | Customize the thread list components.                            |
| **Pinned Message List**  | Customize the pinned message list components.                    |

### Avatars

The `ChatComponentFactory` provides a way to customize the avatars which are
used in the Chat screens. You can customize several types of avatars:

#### ChannelAvatar

Avatar shown in the leading part of the channel items, or in the heading of a
message list:

| ChannelItem                                                                   | MessageListHeader                                                                          |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------ |
| ![ChannelItem](../_assets/component_factory_channel_avatar_channel_item.jpeg) | ![MessageListHeader](../_assets/component_factory_channel_avatar_message_list_header.jpeg) |

To customize the default `ChannelAvatar`,
you need to override the `ChatComponentFactory#ChannelAvatar` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ChannelAvatar(
        modifier: Modifier,
        channel: Channel,
        currentUser: User?,
        onClick: (() -> Unit)?
    ) {
        // Your implementation of the channel avatar
    }
}
```

#### UserAvatar

Avatar shown for a single user, showing his image (if available), or the user
initials. It also shows an online indicator if the user is online. It is used
in several places such as:

- Search results
- Channel members
- Mention suggestions
- `ChannelAvatar` - if the `Channel` is a channel consisting of two members,
  one of which is the current user, or if the `Channel` has only one user.

| Search results                                                                     | Channel members                                                               | Mention suggestions                                                                      |
| ---------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- | ---------------------------------------------------------------------------------------- |
| ![SearchResults](../_assets/component_factory_user_avatar_search_result_item.jpeg) | ![ChannelMembers](../_assets/component_factory_user_avatar_members_list.jpeg) | ![MentionSuggestions](../_assets/component_factory_user_avatar_mention_suggestions.jpeg) |

To customize the default `UserAvatar`, you need to override the
`ChatComponentFactory#UserAvatar` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun UserAvatar(
        modifier: Modifier,
        user: User,
        textStyle: TextStyle,
        showOnlineIndicator: Boolean,
        onlineIndicator: @Composable (BoxScope.() -> Unit),
        onClick: (() -> Unit)?
    ) {
        // Your implementation of the user avatar
    }
}
```

#### GroupAvatar

Avatar which is internally used by the `ChannelAvatar`, to render an avatar for
2 or more users. You can override it if you want to utilize the default
`ChannelAvatar` for channel consisting of 1 or 2 members, but want to customize
the case when the `Channel` has more than 2 members.

To customize the default `GroupAvatar`, you need to override the
`ChatComponentFactory#GroupAvatar` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun GroupAvatar(
        modifier: Modifier,
        users: List<User>,
        shape: Shape,
        textStyle: TextStyle,
        onClick: (() -> Unit)?
    ) {
        // Your implementation of the group avatar
    }
}
```

#### Avatar

Default, low-level component which is independent from `Channel` or `User`. It
is internally used by the `ChannelAvatar` and the `GroupAvatar` to render a
single avatar in the grid, and also by the `UserAvatar` to render the avatar
content. It is also used in other places where we show an avatar for a single
user, where the online indicator is not shown, such as:

- Channel list header - avatar of the currently logged in user
- Quoted messages - avatar of the user who sent the quoted message
- Thread participants in the message footer
- Polls - avatar of users which casted a vote
- User reactions
- Leading content of a message - avatar of the user who sent the message

| Channel list header                                                                | Quoted message                                                            | Thread participants                                                                 | Polls                                                           | User reactions                                                            | Message sender                                                            |
| ---------------------------------------------------------------------------------- | ------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- | --------------------------------------------------------------- | ------------------------------------------------------------------------- | ------------------------------------------------------------------------- |
| ![ChannelListHeader](../_assets/component_factory_avatar_channel_list_header.jpeg) | ![QuotedMessage](../_assets/component_factory_avatar_quoted_message.jpeg) | ![ThreadParticipants](../_assets/component_factory_avatar_thread_participants.jpeg) | ![Polls](../_assets/component_factory_avatar_poll_answers.jpeg) | ![UserReactions](../_assets/component_factory_avatar_user_reactions.jpeg) | ![MessageSender](../_assets/component_factory_avatar_message_sender.jpeg) |

To customize the default `Avatar`, you need to override the
`ChatComponentFactory#Avatar` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun Avatar(
        modifier: Modifier,
        imageUrl: String,
        initials: String,
        shape: Shape,
        textStyle: TextStyle,
        placeholderPainter: Painter?,
        errorPlaceholderPainter: Painter?,
        contentDescription: String?,
        initialsAvatarOffset: DpOffset,
        onClick: (() -> Unit)?
    ) {
        // Your implementation of the avatar
    }
}
```

<admonition type="warning">

The previous `Avatar` method without the `errorPlaceholderPainter` parameter is now deprecated.
Please update your implementation to use the new method signature, which provides better control over fallback behavior when image loading fails.

</admonition>

#### FallbackAvatar

Composable used to render a fallback avatar when the user's image cannot be loaded.
It displays the initials inside a shape, typically a circle. This component is
used as a last resort if both the image and the placeholder fail.

It is used internally by `Avatar` when the image is not available or fails to load.

To customize the fallback avatar, you can override `ChatComponentFactory#FallbackAvatar`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun FallbackAvatar(
        imageUrl: String,
        initials: String,
        modifier: Modifier,
        shape: Shape,
        textStyle: TextStyle,
        avatarOffset: DpOffset,
        onClick: (() -> Unit)?
    ) {
        // Your implementation of the fallback avatar
    }
}
```

### Channel List Header

The `ChannelListHeader` is the default component displayed in the
`ChannelsScreen` header if the `isShowingHeader` flag is set to `true`
(See: [Channels Screen](/chat/docs/sdk/android/compose/channel-components/channels-screen/)
and [Channel List Header](/chat/docs/sdk/android/compose/channel-components/channel-list-header/)).

| Channel List Header                                                                |
| ---------------------------------------------------------------------------------- |
| ![ChannelListHeader](../_assets/component_factory_avatar_channel_list_header.jpeg) |

If you would like to customize the default `ChannelListHeader` while using the
high-level screen component `ChannelsScreen` you can override the corresponding
`ChatComponentFactory` method: `ChannelListHeader`. The method provides some
default data such as the title, the connection state, and the default user
actions, which you can use to build your own channel list header:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ChannelListHeader(
        modifier: Modifier,
        title: String,
        currentUser: User?,
        connectionState: ConnectionState,
        onAvatarClick: (User?) -> Unit,
        onHeaderActionClick: () -> Unit
    ) {
        // Your custom implementation of the channel list header
    }
}
```

The factory also allows for a more granular customization of the channel list
header, by providing different factory methods for the leading, the center and
the trailing content of the header. The default leading content is an avatar of
the currently logged in user, the default center content consists of a title
showing the connection state, while the trailing content displays an additional
custom action button.

You can customize the different parts of
the header by providing your own implementation of the corresponding methods:

- `ChannelListHeaderLeadingContent`
- `ChannelListHeaderCenterContent`
- `ChannelListHeaderTrailingContent`

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.ChannelListHeaderLeadingContent(
        currentUser: User?,
        onAvatarClick: (User?) -> Unit
    ) {
        // Your implementation of the leading content
    }

    @Composable
    override fun RowScope.ChannelListHeaderCenterContent(
        connectionState: ConnectionState,
        title: String
    ) {
        // Your implementation of the center content
    }

    @Composable
    override fun RowScope.ChannelListHeaderTrailingContent(
        onHeaderActionClick: () -> Unit
    ) {
        // Your implementation of the trailing content
    }
}
```

By overriding any of these `ChatComponentFactory` methods, you can easily swap
in and out the `ChannelListHeader`(or specific parts from it), while using the
high-level `ChannelsScreen` component.

<admonition type="note">

If you are not using the high-level screen component `ChannelsScreen`, you can
still use the `ChannelListHeader` component independently from the
`ChatComponentFactory`, and customize its leading/center/trailing content
directly by passing your own content for the
`leadingContent`/`centerContent`/`trailingContent` slots as described in
[Channel List Header](/chat/docs/sdk/android/compose/channel-components/channel-list-header/).

</admonition>

### Channel Items

Similar to the `ChannelListHeader`, the `ChatComponentFactory` provides a way
to customize the channel items which are shown in the list of channels
(in the high-level screen component `ChannelsScreen`, or the bound
`ChannelList` component).

| Channel list item                                                                 |
| --------------------------------------------------------------------------------- |
| ![ChannelListItem](../_assets/component_factory_channel_avatar_channel_item.jpeg) |

To provide your own implementation for the channel item, you can override the
`ChatComponentFactory#ChannelListItemContent`. The method provides the channel
item which needs to be rendered, the default click and long-click actions, and
the current user which you can use to build your own implementation of the
channel item:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun LazyItemScope.ChannelListItemContent(
        channelItem: ItemState.ChannelItemState,
        currentUser: User?,
        onChannelClick: (Channel) -> Unit,
        onChannelLongClick: (Channel) -> Unit,
    ) {
        // Your implementation of the channel item
    }
}
```

The factory also allows for a more granular customization of the channel items,
by providing different factory methods for the leading, the center and
the trailing content of the item. The default leading content is an avatar of
channel, the default center content consists of the channel name and the last
message in the channel, while the trailing content displays the timestamp of
the last message in the channel.

You can customize the leading/center/trailing content of the channel item
separately, but overriding one or more of the dedicated methods:

- `ChannelItemLeadingContent`
- `ChannelItemCenterContent`
- `ChannelItemTrailingContent`

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.ChannelItemLeadingContent(
        channelItem: ItemState.ChannelItemState,
        currentUser: User?,
    ) {
        // Your channel item leading content implementation
    }

    @Composable
    override fun RowScope.ChannelItemCenterContent(
        channelItem: ItemState.ChannelItemState,
        currentUser: User?,
    ) {
        // Your channel item center content implementation
    }

    @Composable
    override fun RowScope.ChannelItemTrailingContent(
        channelItem: ItemState.ChannelItemState,
        currentUser: User?,
    ) {
        // Your channel item trailing content implementation
    }
}
```

By utilizing these methods, you can easily customize the appearance of the
channel items (or parts of them), while still utilizng the features that the
high-level `ChannelsScreen` component provides.

<admonition type="note">

If you are using the bound `ChannelList` component instead of the high-level
`ChannelsScreen`, you can also directly customize the channel items by
providing a custom implementation for the `channelContent` (more details in the
[Channel List](/chat/docs/sdk/android/compose/channel-components/channel-list/)
documentation).

</admonition>

### Message List Header

The `MessageListHeader` is the default component displayed in the
`MessagesScreen` header if the `showHeader` flag is set to `true`
(See: [Messages Screen](/chat/docs/sdk/android/compose/message-components/messages-screen/)
and [Message List Header](/chat/docs/sdk/android/compose/message-components/message-list-header/)).

| Message List Header                                                                        |
| ------------------------------------------------------------------------------------------ |
| ![MessageListHeader](../_assets/component_factory_channel_avatar_message_list_header.jpeg) |

If you would like to customize the default `MessageListHeader` while using the
high-level screen component `MessagesScreen` you can override the corresponding
`ChatComponentFactory` method: `MessageListHeader`. The method provides some
default data such as the `Channel`, the connection state, the typing users, and
the default user actions which you can use to build your own message list
header:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageListHeader(
        modifier: Modifier,
        channel: Channel,
        currentUser: User?,
        connectionState: ConnectionState,
        typingUsers: List<User>,
        messageMode: MessageMode,
        onBackPressed: () -> Unit,
        onHeaderTitleClick: (Channel) -> Unit,
        onChannelAvatarClick: () -> Unit,
    ) {
        // Your implementation of the message list header
    }
}
```

The factory also allows for a more granular customization of the message list
header, by providing different factory methods for the leading, the center and
the trailing content of the header. The default leading content is a back
button, while the center content consists of a title holding the channel name,
and a subtitle showing info about the user count. The trailing content shows
the channel avatar.

You can customize the different parts of the header by providing your own
implementation of the corresponding methods:

- `MessageListHeaderLeadingContent`
- `MessageListHeaderCenterContent`
- `MessageListHeaderTrailingContent`

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.MessageListHeaderLeadingContent(
        onBackPressed: () -> Unit,
    ) {
        // Your implementation for the message list header leading content
    }

    @Composable
    override fun RowScope.MessageListHeaderCenterContent(
        modifier: Modifier,
        channel: Channel,
        currentUser: User?,
        typingUsers: List<User>,
        messageMode: MessageMode,
        onHeaderTitleClick: (Channel) -> Unit,
        connectionState: ConnectionState,
    ) {
        // Your implementation for the message list header center content
    }

    @Composable
    override fun RowScope.MessageListHeaderTrailingContent(
        channel: Channel,
        currentUser: User?,
        onClick: () -> Unit,
    ) {
        // Your implementation for the message list header trailing content
    }
}
```

By overriding any of these `ChatComponentFactory` methods, you can easily swap
in and out the `MessageListHeader`(or specific parts from it), while using the
high-level `MessagesScreen` component.

<admonition type="note">

You can also customize the `MessageListHeader` from the `MessagesScreen` by
passing your implemenation in the `topBarContent` slot.

</admonition>

<admonition type="note">

If you are not using the high-level screen component `MessagesScreen`, you can
still use the `MessageListHeader` component independently from the
`ChatComponentFactory`, and customize its leading/center/trailing content
directly by passing your own content for the
`leadingContent`/`centerContent`/`trailingContent` slots as described in
[Message List Header](/chat/docs/sdk/android/compose/message-components/message-list-header/).

</admonition>

### Message List Background

You can customize the background of the `MessageList` by overriding the
`ChatComponentFactory#MessageListBackground` composable. In this composable,
you can render any sort of background you want, such as a gradient, an image,
or even a more complex background with multiple layers, and it will be rendered
behind the message list items.

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageListBackground() {
        // Your implementation for the message list background
    }
}
```

### Message Items

#### MessageListItemContent

The message list item content represents the entire content of a regular chat message.

![MessageListItemContent](../_assets/component_factory_message_list_item_content.png)

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    public fun LazyItemScope.MessageListItemContent(
      messageItem: MessageItemState,
      reactionSorting: ReactionSorting,
      onPollUpdated: (Message, Poll) -> Unit,
      onCastVote: (Message, Poll, Option) -> Unit,
      onRemoveVote: (Message, Poll, Vote) -> Unit,
      selectPoll: (Message, Poll, PollSelectionType) -> Unit,
      onClosePoll: (String) -> Unit,
      onAddPollOption: (Poll, String) -> Unit,
      onLongItemClick: (Message) -> Unit,
      onThreadClick: (Message) -> Unit,
      onReactionsClick: (Message) -> Unit,
      onGiphyActionClick: (GiphyAction) -> Unit,
      onMediaGalleryPreviewResult: (MediaGalleryPreviewResult?) -> Unit,
      onQuotedMessageClick: (Message) -> Unit,
      onUserAvatarClick: ((User) -> Unit)?,
      onMessageLinkClick: ((Message, String) -> Unit)?,
      onUserMentionClick: (User) -> Unit,
      onAddAnswer: (Message, Poll, String) -> Unit,
    ) {
        // Custom message list item content implementation
    }
}
```

#### MessageTextContent

This allows customization of the text content inside a message bubble.

![MessageTextContent](../_assets/component_factory_message_text_content.png)

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageTextContent(
        message: Message,
        currentUser: User?,
        onLongItemClick: (Message) -> Unit,
        onLinkClick: ((Message, String) -> Unit)?,
        onUserMentionClick: (User) -> Unit
    ) {
        // Custom message text content implementation
    }
}
```

#### MessageItemFooterContent

This allows customization of the entire footer of a message,
which includes timestamps and message status.

![MessageItemFooterContent](../_assets/component_factory_message_item_footer_content.png)

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ColumnScope.MessageItemFooterContent(
        messageItem: MessageItemState
    ) {
        // Custom message item footer implementation
    }
}
```

#### MessageFooterStatusIndicator

This allows customization of the status indicator of a message,
which includes the read status and read count.

![MessageFooterStatusIndicator](../_assets/component_factory_message_footer_status_indicator.png)

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageFooterStatusIndicator(
        modifier: Modifier,
        message: Message,
        isMessageRead: Boolean,
        readCount: Int
    ) {
        // Custom status indicator implementation
    }
}
```

#### Message list date separator

In addition to the actual message items, you can also utilize the `ChatComponentFactory` to
customize the different parts of the message list, such as the date separators appearing between
messages sent on different days:

| Message list date separator                                                                |
| ------------------------------------------------------------------------------------------ |
| ![MessageListDateSeparator](../_assets/component_factory_message_list_date_separator.jpeg) |

To provide a custom appearance for the date separator, you can override the
`ChatComponentFactory#MessageListDateSeparatorItemContent` method. The method provides the
`DateSeparatorItemState` from where you can extract the date which needs to be rendered:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

  @Composable
  override fun LazyItemScope.MessageListDateSeparatorItemContent(dateSeparatorItem: DateSeparatorItemState) {
    // Your implementation for the message list date separator
  }
}
```

#### Message list unread separator

Similarly to the date separator, you can also customize the appearance of the unread separator shown
in the `MessageList` after the last read message:

| Message list unread separator                                                                                            |
| ------------------------------------------------------------------------------------------------------------------------ |
| ![component_factory_message_list_unread_separator.jpeg](../_assets/component_factory_message_list_unread_separator.jpeg) |

To provide a custom appearance for the unread separator, you can override the
`ChatComponentFactory#MessageListUnreadSeparatorItemContent`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun LazyItemScope.MessageListUnreadSeparatorItemContent(unreadSeparatorItem: UnreadSeparatorItemState) {
        // Your implementation for the unread separator
    }
}
```

#### System message item

Utilizing the `ChatComponentFactory`, you can also customize the appearance of the system messages
in the `MessageList`:

| System message item                                                                 |
| ----------------------------------------------------------------------------------- |
| ![SystemMessageItem](../_assets/component_factory_message_list_system_message.jpeg) |

To provide a custom appearance for the system message item, you can override the
`ChatComponentFactory#MessageListSystemItemContent` method. The method provides the
`SystemMessageItemState` which you can use to extract the system `Message` that needs to be shown:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun LazyItemScope.MessageListSystemItemContent(systemMessageItem: SystemMessageItemState) {
        // Your implementation for the system message item
    }
}
```

#### Message list typing indicator

The typing indicator is an item which is placed at the bottom of the `MessageList`, and is shown
when 1 or more users are currently typing a message. By default, the SDK does not provide a typing
indicator implementation, so if you would like to show it, you would need to override the
`ChatComponentFactory#MessageListTypingIndicatorItemContent` method, and provide your own UI for it.
The method provides the `TypingItemState` from which you can extract the currently typing users:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun LazyItemScope.MessageListTypingIndicatorItemContent(typingItem: TypingItemState) {
        // Your implementation of the typing indicator, ex:
        Text("${typingItem.typingUsers.size} users are typing...")
    }
}
```

### Message Composer

The `ChatComponentFactory` provides a way to customize different parts of the
`MessageComposer` when it is used as part of the high-level screen component
`MessagesScreen`, by simply overriding the corresponding factory method,
without the need to re-implement big parts of the UI.

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can use the `ChatComponentFactory`, but
you can also customize most of the components by passing custom implementation
in the specific slots. More details can be found in the
[Message Composer](/chat/docs/sdk/android/compose/message-components/message-composer/)
docs.

</admonition>

The default composer consists of several basic components:

- Attachments button
- Commands button
- Input field
- Send button

| Message composer                                                     |
| -------------------------------------------------------------------- |
| ![MessageComposer](../_assets/component_factory_composer_empty.jpeg) |

Let's see how you can customize each one of the base composer components:

#### Composer label

By default, when there is no message entered in the composer, it shows a simple
"Send a message" label. To override the default text with a new one, or to
completely replace the component with a different one, you can override the
`ChatComponentFactory#MessageComposerLabel`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerLabel(state: MessageComposerState) {
        // Your implementation of the composer label
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `label` slot.

</admonition>

#### Composer input

If you need to modify the whole input field, you can override the method:
`ChatComponentFactory#MessageComposerInput`, which provides the current
`MessageComposerState`, and the callbacks required to update the state backing
the composer input field: `onInputChanged` and `onAttachmentRemoved`. It also
provides the aforementioned `label` component, so that you can re-use the
default composer label in your custom input field:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.MessageComposerInput(
        state: MessageComposerState,
        onInputChanged: (String) -> Unit,
        onAttachmentRemoved: (Attachment) -> Unit,
        label: @Composable (MessageComposerState) -> Unit,
    ) {
        // Your custom implementation of the composer input field
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `input` slot.

</admonition>

#### Attachments button

The first button in the default message composer - the "Attachments" button can
be customized by overriding the
`ChatComponentFactory#MessageComposerAttachmentsButton` method. It provides two
arguments:

- `enabled` - flag instructing whether the button should be enabled/disabled
- `onClick` - the action to be taken when the button is clicked. By default,
  calling this method will result in the opening of the attachments picker.

If you want to update the appearance of the button, but at the same time to
also preserve the existing behaviour, we strongly recommend to respect the
`enabled` flag, and to call the provided `onClick` lambda in your custom button
implementation.

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.MessageComposerAttachmentsButton(
        enabled: Boolean,
        onClick: () -> Unit,
    ) {
        // Your custom implementation of the 'Attachments' button
    }
}
```

#### Commands button

Similar to the "Attachments" button, you can easily customize the second button
shown in the default message composer - the "Commands" button.
You can do that by overriding the
`ChatComponentFactory#MessageComposerCommandsButton` method. It provides
several arguments:

- `hasCommandSuggestions` - indicator if the commands suggestion menu is active
- `enabled` - flag instructing whether the button should be enabled/disabled
- `onClick` - the action to be taken when the button is clicked. By default,
  calling this method will result in the opening/closing of the commands
  suggestion menu.

If you want to update the appearance of the button, but at the same time to
also preserve the existing behaviour, we strongly recommend to respect the
`enabled` flag, and to call the provided `onClick` lambda in your custom button
implementation.

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.MessageComposerCommandsButton(
        hasCommandSuggestions: Boolean,
        enabled: Boolean,
        onClick: () -> Unit,
    ) {
        // Your implementation of the commands button
    }
}
```

#### Integrations

The previously mentioned "Attachments" and "Commands" buttons can also be
customized as a group via `ChatComponentFactory#MessageComposerIntegrations`.
The integrations represent the 'leading' content of the message composer, and
it contains both the "Attachments" and "Commands" buttons. So if you want to
customize, or maybe even remove the whole content before the input field, you
can do that by overriding the following:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.MessageComposerIntegrations(
        state: MessageComposerState,
        onAttachmentsClick: () -> Unit,
        onCommandsClick: () -> Unit,
    ) {
        // Your implementation of the composer integrations
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `integrations` slot.

</admonition>

#### Send button

The "Send" button shown after the input field in the default message composer
can be customized via the
`ChatComponentFactory#MessageComposerSendButton`. The method provides couple of
arguments:

- `enabled` - flag instructing whether the button should be enabled/disabled
- `isInputValid` - flag indicating if the currently entered input passed the
  validation checks and can be submitted
- `onClick` - the action to be taken when the button is clicked. By default,
  calling this method will result in attempting to send the currently entered
  message to the channel.

If you want to update the appearance of the button, but at the same time to
also preserve the existing behaviour, we strongly recommend to respect the
`enabled` and `isInputValid` flags, and to call the provided `onClick` lambda
in your custom button implementation.

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerSendButton(
        enabled: Boolean,
        isInputValid: Boolean,
        onClick: () -> Unit,
    ) {
        // Your implementation of the send button
    }
}
```

#### Audio record button

<admonition type="note">

The "Audio record" button and voice messages are disabled by default.
To enable it, you need to set the `AudioRecordingTheme.enabled` flag to `true`,
which is defined in the `MessageComposerTheme`.

</admonition>

The "Audio record" button in the message composer is used to record and send
audio messages to the channel. You can start the recording process by pressing
and holding the "Audio record" button.

| Audio Record Button                                                           |
| ----------------------------------------------------------------------------- |
| ![AudioRecordButton](../_assets/component_factory_composer_audio_record.jpeg) |

You can customize this button by overriding the
`ChatComponentFactory#MessageComposerAudioRecordButton`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerAudioRecordButton(
        state: RecordingState,
        recordingActions: AudioRecordingActions,
    ) {
        // Your implementation of the audio record button
    }
}
```

#### Composer trailing content

Similar to how the "Attachments" and "Commands" buttons are grouped in a single
"Integrations" component, the "Send" and "Audio record" buttons are grouped in
the "Trailing content" component. You can customize the trailing content by
overriding the `ChatComponentFactory#MessageComposerTrailingContent`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerTrailingContent(
        state: MessageComposerState,
        onSendClick: (String, List<Attachment>) -> Unit,
        recordingActions: AudioRecordingActions,
    ) {
        // Your implementation of the composer trailing content
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `trailingContent` slot.

</admonition>

#### Mentions popup content

When the user enters the `@` character in the message composer, it is detected
as a mention action, and a popup showing all suggested users that can be
mentioned is shown:

| Mentions popup                                                                                            |
| --------------------------------------------------------------------------------------------------------- |
| ![MessageComposerMentionsPopupContent](../_assets/component_factory_user_avatar_mention_suggestions.jpeg) |

You can customize this popup dialog by overriding the
`ChatComponentFactory#MessageComposerMentionsPopupContent` method, which
provides:

- `mentionSuggestions` - the list of users which match the mention string
- `onMentionSelected` - the action to be taken when a suggestion is clicked. By
  default, calling this method results in appending the full user name to the `@`
  character in the current message.

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerMentionsPopupContent(
        mentionSuggestions: List<User>,
        onMentionSelected: (User) -> Unit,
    ) {
        // Your implementation of the the mentions popup content
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `mentionPopupContent` slot.

</admonition>

If you want to keep the default layout of the popup content, and only change
the content of the mention items, you can do that by overriding the specific
`ChatComponentFactory#MessageComposerMentionSuggestionItem` method. This method
provides the `User` for which the item will be rendered, and the lambda to be
invoked when the item is clicked. You can use these arguments to build your own
custom mention suggestion item:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerMentionSuggestionItem(
        user: User,
        onMentionSelected: (User) -> Unit,
    ) {
        // Your implementation for the mention suggestion item
    }
}
```

As with other similar items, the `ChatComponentFactory` provides a way for
granular customization of the mention suggestion items, by overriding the
corresponding methods for the leading/center/trailing content of the items.
The default leading content displays the user avatar, while the center content
displays the user name and ID. The trailing content displays a decorative `@`
icon. You can customize or even remove any of these parts of the items by
overriding the corresponding methods:

- `MessageComposerMentionSuggestionItemLeadingContent`
- `MessageComposerMentionSuggestionItemCenterContent`
- `MessageComposerMentionSuggestionItemTrailingContent`

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.MessageComposerMentionSuggestionItemLeadingContent(
        user: User,
    ) {
        // Your implementation of the leading content
    }

    @Composable
    override fun RowScope.MessageComposerMentionSuggestionItemCenterContent(
        user: User,
    ) {
        // Your implementation of the center content
    }

    @Composable
    override fun RowScope.MessageComposerMentionSuggestionItemTrailingContent(
        user: User,
    ) {
        // Your implementation of the trailing content
    }
}
```

#### Commands popup content

Clicking on the "Commands" button from the message composer, or starting your
message with the `/` character results in showing a popup which displays all
the possible commands that can be performed in the channel (ex. `/mute`,
`/unmute`).

| Commands popup                                                                              |
| ------------------------------------------------------------------------------------------- |
| ![MessageComposerCommandsPopupContent](../_assets/component_factory_composer_commands.jpeg) |

You can customize this popup dialog by overriding the
`ChatComponentFactory#MessageComposerCommandsPopupContent` method, which
provides:

- `commandSuggestions` - the list of commands which match the command string
- `onCommandSelected` - the action to be taken when a suggestion is clicked. By
  default, calling this method results in appending the full command to the `/`
  character in the current message.

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerCommandsPopupContent(
        commandSuggestions: List<Command>,
        onCommandSelected: (Command) -> Unit,
    ) {
        // Your implementation of the command suggestions popup
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `commandPopupContent` slot.

</admonition>

If you want to keep the default layout of the popup content, and only change
the content of the command items, you can do that by overriding the specific
`ChatComponentFactory#MessageComposerCommandSuggestionItem` method. This method
provides the `Command` for which the item will be rendered, and the lambda to be
invoked when the item is clicked. You can use these arguments to build your own
custom command suggestion item:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerCommandSuggestionItem(
        command: Command,
        onCommandSelected: (Command) -> Unit,
    ) {
        // Your implementation of the command suggestion item
    }
}
```

As with other similar items, the `ChatComponentFactory` provides a way for
granular customization of the command suggestion items, by overriding the
corresponding methods for the leading/center content of the items. The default
leading content displays the command icon, while the center content displays
the full name of the command, and an example of how the whole command string
should look like. You can customize or even remove any of these parts of the
items by overriding the corresponding methods:

- `MessageComposerCommandSuggestionItemLeadingContent`
- `MessageComposerCommandSuggestionItemCenterContent`

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.MessageComposerCommandSuggestionItemLeadingContent(
        command: Command,
    ) {
        // Your implementation of the leading content
    }

    @Composable
    override fun RowScope.MessageComposerCommandSuggestionItemCenterContent(
        modifier: Modifier,
        command: Command,
    ) {
        // Your implementation of the center content
    }
}
```

#### Composer header

The message composer header is a component which appears only in specific
scenarios, such as:

- Editing a message
- Replying to a message
- Adding a URL in the message

| Edit message                                                                  | Reply to message                                                                | Add URL                                                                       |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------- | ----------------------------------------------------------------------------- |
| ![ComposerHeaderEdit](../_assets/component_factory_composer_header_edit.jpeg) | ![ComposerHeaderReply](../_assets/component_factory_composer_header_reply.jpeg) | ![ComposerHeaderLink](../_assets/component_factory_composer_header_link.jpeg) |

If you want to fully replace the default composer header implementations, you
can do to that by overriding the `ChatComponentFactory#MessageComposerHeader`.
The method provides the current `state` of the composer, which you can use to
build your own implementation of the header. It also provides the `onCancel`
and `onLinkPreviewClick` lambdas, which you can call if you want to dismiss
the header, or to open the currently visible link preview:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ColumnScope.MessageComposerHeaderContent(
        state: MessageComposerState,
        onCancel: () -> Unit,
        onLinkPreviewClick: ((LinkPreview) -> Unit)?,
    ) {
        // Your implementation of the composer header
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `headerContent` slot.

</admonition>

You can also customize the the different states of the composer header
separately: Overriding the
`ChatComponentFactory#MessageComposerMessageInputOptions` will result in
changing the Edit/Reply message header content, while overriding the
`ChatComponentFactory#MessageComposerLinkPreview` will result in changing the
URL preview content:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerMessageInputOptions(
        modifier: Modifier,
        activeAction: MessageAction,
        onCancel: () -> Unit,
    ) {
        // Your implementation of the Edit/Reply header
    }

    @Composable
    override fun MessageComposerLinkPreview(
        modifier: Modifier,
        linkPreview: LinkPreview,
        onClick: ((LinkPreview) -> Unit)?,
    ) {
        // Your implementation of the link preview
    }
}
```

#### Composer footer

The message composer footer is a component which only appears when the user
replies in a thread, and it shows a checkbox that the user can toggle on, to
send the message as a direct message as well.

| Thread reply                                                         |
| -------------------------------------------------------------------- |
| ![ComposerFooter](../_assets/component_factory_composer_footer.jpeg) |

To customize this component, you can override the
`ChatComponentFactory#MessageComposerFooterContent` method. The method provides
the current `state` of the composer, which you can use to build your own
implementation of the footer. It also provides a `onAlsoSendToChannelSelected`
lambda, which is invoked when the checkmark is updated:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ColumnScope.MessageComposerFooterContent(
        state: MessageComposerState,
        onAlsoSendToChannelSelected: (Boolean) -> Unit,
    ) {
        // Your implementation of the footer content
    }
}
```

<admonition type="note">

If you are using the bound/stateless component `MessageComposer` directly
instead of the `MessagesScreen`, you can also customize this component by
providing your implementation in the `footerContent` slot.

</admonition>

#### Quoted message

Another component that can be customized via the `ChatComponentFactory` is the
quoted message which is shown in the composer when the user replies to a
message:

| Quoted message                                                              |
| --------------------------------------------------------------------------- |
| ![QuotedMessage](../_assets/component_factory_composer_quoted_message.jpeg) |

You can customize the appearance of the quoted message in the message composer
by overriding the `ChatComponentFactory#MessageComposerQuotedMessage`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageComposerQuotedMessage(
        modifier: Modifier,
        state: MessageComposerState,
        quotedMessage: Message,
    ) {
        // Your implementation of the quoted message
    }
}
```

### Attachments Picker

The `AttachmentsPicker` is a component that allows the user to browse and
select media files to be sent in a message. The type of attachments that it
supports and its appearance can be customized via the
`ChatTheme#attachmentsPickerTabFactories` property, with which you can provide
a list of custom `AttachmentsPickerTabFactory` instances (see:
[Attachments Picker](/chat/docs/sdk/android/compose/message-components/attachments-picker/)).

The `ChatComponentFactory` provides some additional customizations that you can
apply to the default attachments picker, such as modifying the `Add (>)` button
in the picker header:

| Attachments picker                                                             |
| ------------------------------------------------------------------------------ |
| ![AttachmentsPicker](../_assets/component_factory_attachments_picker_add.jpeg) |

You can customize the appearance of the "Add" button in the attachments picker
by overriding the `ChatComponentFactory#AttachmentsPickerAddButton` method.
The method provides two arguments:

- `hasPickedAttachments` - flag indicating if the user has selected any
  attachments
- `onClick` - the action to be taken when the button is clicked. By default,
  calling this method will result in closing the attachments picker and sending
  the selected attachments to the message composer.

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

  @Composable
  override fun AttachmentsPickerSendButton(
    hasPickedAttachments: Boolean,
    onClick: () -> Unit,
  ) {
    // Your implementation for the "Add" button in the attachments picker
  }
}
```

### Menus

The `ChatComponentFactory` provides a way to customize different menus used in
the Chat screens:

- Channel options menu
- Message options menu
- Reactions menu

#### Channel menu

The channel menu provides actions that the user can perform over a given
channel.

| Channel menu                                                   |
| -------------------------------------------------------------- |
| ![ChannelMenu](../_assets/component_factory_channel_menu.jpeg) |

To provide a custom implementation of the channel menu, you need to override
the `ChatComponentFactory#ChannelMenu` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ChannelMenu(
        modifier: Modifier,
        selectedChannel: Channel,
        isMuted: Boolean,
        currentUser: User?,
        onChannelOptionClick: (ChannelAction) -> Unit,
        onDismiss: () -> Unit
    ) {
        // Your implementation of the channel menu
    }
}
```

The `ChatComponentFactory` also provides a way for more granular customization
of this menu. You can separately override/customize the header of the menu:

| Channel menu header                                                         |
| --------------------------------------------------------------------------- |
| ![ChannelMenuHeader](../_assets/component_factory_channel_menu_header.jpeg) |

by overriding the `ChatComponentFactory#ChannelMenuHeaderContent`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ChannelMenuHeaderContent(modifier: Modifier, selectedChannel: Channel, currentUser: User?) {
        // Your implementation for the channel menu header
    }
}
```

Similarly, you can customize the main content of the menu - the actual channel
options:

| Channel menu options                                                          |
| ----------------------------------------------------------------------------- |
| ![ChannelMenuOptions](../_assets/component_factory_channel_menu_options.jpeg) |

by overriding the `ChatComponentFactory#ChannelMenuOptions`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ChannelMenuOptions(
        modifier: Modifier,
        onChannelOptionClick: (ChannelAction) -> Unit,
        channelOptions: List<ChannelOptionState>
    ) {
        // Your implementation for the channel menu options
    }
}
```

Additionally, if you want to keep the default channel menu layout and content,
but want to only modify the appearance of the option items, you can do that by
overriding the `ChatComponentFactory#ChannelOptionsItem` method. This method
provides the `ChannelOptionState`, which you can use to retrieve the information
about the item to be rendered, like the title, the icon, or the action:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ChannelOptionsItem(modifier: Modifier, option: ChannelOptionState, onClick: () -> Unit) {
        // Your implementation of the channel option item
    }
}
```

For an even more fine-grained customisation, there is also a method which
allows customizing of the icons shown in the channel menu option items:
`ChatComponentFactory#ChannelOptionsItemLeadingIcon`. By overriding this
method you can provide custom icons for the items, change the icon for a
different content, or even completely remove the icons from the items:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ChannelOptionsItemLeadingIcon(modifier: Modifier, option: ChannelOptionState) {
        // Your implementation for the leading icon
    }
}
```

#### Message menu

The message menu provides actions that the user can perform over a given
message.

| Message menu                                                   |
| -------------------------------------------------------------- |
| ![MessageMenu](../_assets/component_factory_message_menu.jpeg) |

To provide a custom implementation of the message menu, you need to override
the `ChatComponentFactory#MessageMenu` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageMenu(
        modifier: Modifier,
        message: Message,
        messageOptions: List<MessageOptionItemState>,
        ownCapabilities: Set<String>,
        onMessageAction: (MessageAction) -> Unit,
        onShowMore: () -> Unit,
        onDismiss: () -> Unit
    ) {
        // Your implementation of the message menu
    }
}
```

Similar to the channel menu, you can separately customize the header content of
the message menu, which holds the available reactions:

| Message menu header                                                         |
| --------------------------------------------------------------------------- |
| ![MessageMenuHeader](../_assets/component_factory_message_menu_header.jpeg) |

by overriding the `ChatComponentFactory#MessageMenuHeaderContent`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageMenuHeaderContent(
        modifier: Modifier,
        message: Message,
        messageOptions: List<MessageOptionItemState>,
        onMessageAction: (MessageAction) -> Unit,
        ownCapabilities: Set<String>,
        onShowMore: () -> Unit,
        reactionTypes: Map<String, ReactionIcon>,
        showMoreReactionsIcon: Int
    ) {
        // Your implementation of the message menu header (reactions)
    }
}
```

Similarly, you can customize the main content of the menu - the actual message
options:

| Message menu options                                                          |
| ----------------------------------------------------------------------------- |
| ![MessageMenuOptions](../_assets/component_factory_message_menu_options.jpeg) |

by overriding the `ChatComponentFactory#MessageMenuOptions`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageMenuOptions(
        modifier: Modifier,
        message: Message,
        options: List<MessageOptionItemState>,
        onMessageOptionSelected: (MessageOptionItemState) -> Unit
    ) {
        // Your implementation of the message menu options
    }
}
```

Additionally, if you want to keep the default message menu layout and content,
but want to only modify the appearance of the option items, you can do that by
overriding the `ChatComponentFactory#MessageMenuOptionsItem` method. This method
provides the `MessageOptionItemState`, which you can use to retrieve the
information about the item to be rendered, like the title, the icon, or the
action:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageMenuOptionsItem(
        modifier: Modifier,
        option: MessageOptionItemState,
        onMessageOptionSelected: (MessageOptionItemState) -> Unit
    ) {
        // Your implementation of the message option item
    }
}
```

For an even more fine-grained customisation, there is also a method which
allows customizing of the icons shown in the message menu option items:
`ChatComponentFactory#MessageMenuOptionsItemLeadingContent`. By overriding this
method you can provide custom icons for the items, change the icon for a
different content, or even completely remove the icons from the items:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageMenuOptionsItemLeadingContent(modifier: Modifier, option: MessageOptionItemState) {
        // Your implementation for the leading icon
    }
}
```

#### Channel and Message menu

In the previous sections, we demonstrated how to customize the channel and the
message menus separately, using the `ChatComponentFactory`.

The component factory also provides a simpler way, to customize the option
items for both the channel and message menu, by overriding the
`ChatComponentFactory#MessageMenuItem`. For example, if you would like
to remove the leading icons from the options items in both channel and
message menus, you can do something like:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MenuOptionItem(
        modifier: Modifier,
        onClick: () -> Unit,
        leadingIcon: @Composable (RowScope.() -> Unit),
        title: String,
        titleColor: Color,
        style: TextStyle,
        itemHeight: Dp,
        verticalAlignment: Alignment.Vertical,
        horizontalArrangement: Arrangement.Horizontal
    ) {
        // Call super.MenuOptionItem, but override the leading icon composable
        super.MenuOptionItem(
            modifier = modifier,
            onClick = onClick,
            leadingIcon = {
                // Remove leading icon
                Spacer(modifier = Modifier.width(16.dp))
            },
            title = title,
            titleColor = titleColor,
            style = style,
            itemHeight = itemHeight,
            verticalAlignment = verticalAlignment,
            horizontalArrangement = horizontalArrangement,
        )
    }
}
```

This would result in menus like:

| Channel menu                                                                        | Message menu                                                                        |
| ----------------------------------------------------------------------------------- | ----------------------------------------------------------------------------------- |
| ![ChannelMenuCustomized](../_assets/component_factory_channel_menu_customized.jpeg) | ![MessageMenuCustomized](../_assets/component_factory_message_menu_customized.jpeg) |

#### Reactions menu

The reactions menu appears when the user taps on the reaction icon in a message
header. It shows an overview of all the reactions for a given message and
provides the option for adding/changing/removing the current user's reaction.

| Reactions menu                                                     |
| ------------------------------------------------------------------ |
| ![ReactionsMenu](../_assets/component_factory_reactions_menu.jpeg) |

To customize the reactions menu, you need to override the `ChatComponentFactory#ReactionsMenu` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ReactionsMenu(
        modifier: Modifier,
        currentUser: User?,
        message: Message,
        onMessageAction: (MessageAction) -> Unit,
        onShowMoreReactionsSelected: () -> Unit,
        ownCapabilities: Set<String>,
        onDismiss: () -> Unit,
    ) {
        // Your implementation of the reactions menu
    }
}
```

Similar to the other menus, you can separately customize the header content of
the reactions menu, which holds the available reactions:

| Reactions menu header                                                           |
| ------------------------------------------------------------------------------- |
| ![ReactionsMenuHeader](../_assets/component_factory_reactions_menu_header.jpeg) |

by overriding the `ChatComponentFactory#ReactionsMenuHeaderContent`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ReactionsMenuHeaderContent(
        modifier: Modifier,
        message: Message,
        reactionTypes: Map<String, ReactionIcon>,
        onMessageAction: (MessageAction) -> Unit,
        onShowMoreReactionsSelected: () -> Unit,
        showMoreReactionsIcon: Int,
    ) {
        // Your implementation of the reactions menu header content
    }
}
```

Similarly, you can customize the main content of the menu - the overview of all
reactions:

| Reactions menu overview                                                            |
| ---------------------------------------------------------------------------------- |
| ![ReactionsMenuOverview](../_assets/component_factory_reactions_menu_options.jpeg) |

by overriding the `ChatComponentFactory#ReactionsMenuCenterContent`:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ReactionsMenuCenterContent(
        modifier: Modifier,
        userReactions: List<UserReactionItemState>,
    ) {
        // Your implementation of the reactions menu center content
    }
}
```

#### Reaction options

The previously described "Message menu" and "Reactions menu" reuse the same
reactions header component, and the `ChatComponentFactory` provides a way to
customize this component generally, without the need to customize both menus
separately. You can achieve this by overriding the
`ChatComponentFactory#ReactionMenuOptions` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ReactionMenuOptions(
        modifier: Modifier,
        message: Message,
        reactionTypes: Map<String, ReactionIcon>,
        onMessageAction: (MessageAction) -> Unit,
        onShowMoreReactionsSelected: () -> Unit,
        showMoreReactionsIcon: Int,
    ) {
        // Your implementation for the reactions menu options
    }
}
```

If you want to only customize the appearance of the individual reaction items
you can override the `ChatComponentFactory#ReactionMenuOptionItem` method. This
method provides the `ReactionOptionItemState`, which you can use to retrieve the
information about the item to be rendered, and the `onReactionSelected` lambda,
which you can call when the item is clicked:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ReactionMenuOptionItem(
        modifier: Modifier,
        option: ReactionOptionItemState,
        onReactionOptionSelected: (ReactionOptionItemState) -> Unit,
    ) {
        // Your implementation for the reaction menu item
    }
}
```

#### Extended reactions menu

The reactions picker menu by default shows up to 5 items. If there are more
possible reactions to show, the "Show more" item is displayed:

| Reactions menu show more                                                             |
| ------------------------------------------------------------------------------------ |
| ![ReactionsMenuShowMore](../_assets/component_factory_reactions_menu_show_more.jpeg) |

To customize the appearance of the "Show more" item in the reactions menu, you
can override the `ChatComponentFactory#ReactionsMenuShowMore` method. The
method provides the `onShowMoreReactionsSelected` lambda, which you can call to
open the "Extended reactions menu":

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ReactionMenuShowMore(
        modifier: Modifier,
        onShowMoreReactionsSelected: () -> Unit,
        showMoreReactionsIcon: Int,
    ) {
        // Your implementation of the "Show more reactions" item
    }
}
```

Clicking on the "Show more" item will open the "Extended reactions menu":

| Extended reactions menu                                                             |
| ----------------------------------------------------------------------------------- |
| ![ExtendedReactionsMenu](../_assets/component_factory_reactions_menu_extended.jpeg) |

To customize the appearance of the "Extended reactions menu", you can override
the `ChatComponentFactory#MessageReactionPicker` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageReactionPicker(
        modifier: Modifier,
        message: Message,
        onMessageAction: (MessageAction) -> Unit,
        onDismiss: () -> Unit,
    ) {
        // Your implementation for the 'extended' reactions picker
    }
}
```

This extended reactions picker is built from 2 separate components which can be
customized separately:

- The header content, which is empty by default.
- The center content, which displays the list of all reactions.

To customize (add) a header to the extended reactions picker, you can override
the `ChatComponentFactory#MessageReactionPickerHeaderContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageReactionPickerHeaderContent(
        modifier: Modifier,
        message: Message,
        onMessageAction: (MessageAction) -> Unit,
        onDismiss: () -> Unit,
    ) {
        // Your implementation of the extended reactions picker header
    }
}
```

And to customize the content which displays the list of all reactions, you can
override the `ChatComponentFactory#MessageReactionPickerCenterContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun MessageReactionPickerCenterContent(
        modifier: Modifier,
        message: Message,
        onMessageAction: (MessageAction) -> Unit,
        reactionTypes: Map<String, ReactionIcon>,
        onDismiss: () -> Unit,
    ) {
        // Your implementation of the extended reactions picker content
    }
}
```

If you want to only customize the appearance of the individual reaction items
you can override the `ChatComponentFactory#ExtendedReactionMenuOptionItem`
method. This method provides the `ReactionOptionItemState`, which you can use
to retrieve the information about the item to be rendered, and the
`onReactionOptionSelected` lambda, which you can call when the item is clicked:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ExtendedReactionMenuOptionItem(
        modifier: Modifier,
        option: ReactionOptionItemState,
        onReactionOptionSelected: (ReactionOptionItemState) -> Unit,
    ) {
        // Your implementation of the reaction menu item
    }
}
```

<admonition type="note">

The `ExtendedReactionMenuOptionItem` internally uses the
`ReactionMenuOptionItem`, so overriding the `ReactionMenuOptionItem` will also
result in overriding the `ExtendedReactionMenuOptionItem`.

</admonition>

### Thread List

The `ThreadList` component is used to display a list of all threads for a given
user (See [Thread List](/chat/docs/sdk/android/compose/thread-list/)).

| Thread list                                                       |
| ----------------------------------------------------------------- |
| ![ThreadList](../_assets/compose_default_thread_list_content.png) |

As an alternative to using the composable slot parameters provided by the
`ThreadList` component, you can also customize the appearance of the threads
via the `ChatComponentFactory`.

To customize the "New threads" banner which displays the number of new unseen
threads, you can override the
`ChatComponentFactory#ThreadListUnreadThreadsBanner` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ThreadListUnreadThreadsBanner(
        unreadThreads: Int,
        onClick: () -> Unit,
    ) {
        // Your implementation of the unread threads banner
    }
}
```

<admonition type="note">

Overriding the `ThreadListUnreadThreadsBanner` is the same as passing a custom
implementation for the `ThreadList#unreadThreadsBanner` slot.

</admonition>

To customize the items in the thread list, you can override the
`ChatComponentFactory#ThreadListItem` method. This method provides the `Thread`
data which you can use to build your own implementation of the thread item, and
the `onThreadClick` lambda which you can call when the item is clicked:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ThreadListItem(
        thread: Thread,
        currentUser: User?,
        onThreadClick: (Thread) -> Unit
    ) {
        // Your implementation of the thread item
    }
}
```

<admonition type="note">

Overriding the `ThreadListItem` is the same as passing a custom
implementation for the `ThreadList#itemContent` slot.

</admonition>

Similar to other list items, the `ChatComponentFactory` provides a way for a
more granular customization of the thread list items. It provides methods for
customization of the:

- Thread title - Shows the thread icon and the channel name in which the thread
  exists.
- Reply to - Shows a preview of the thread root message.
- Unread count indicator - Shows the number of unread messages
  in the thread.
- Latest reply - Shows the latest message in the thread.

To customize one or more of these parts of the thread list items, you can
override any of the corresponding methods:

- `ThreadListItemTitle`
- `ThreadListItemReplyToContent`
- `ThreadListItemUnreadCountContent`
- `ThreadListItemLatestReplyContent`

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ThreadListItemTitle(thread: Thread, channel: Channel, currentUser: User?) {
        // Your implementation of the thread title
    }

    @Composable
    override fun RowScope.ThreadListItemReplyToContent(thread: Thread) {
        // Your implementation of the thread root message content
    }

    @Composable
    override fun RowScope.ThreadListItemUnreadCountContent(unreadCount: Int) {
        // Your implementation of the unread count content
    }

    @Composable
    override fun ThreadListItemLatestReplyContent(thread: Thread, currentUser: User?) {
        // Your implementation of the latest reply content
    }
}
```

The `ChatComponentFactory` also provides a way for customizing the loading
content of the thread list. You can customize the default loading indicator by
overriding the `ChatComponentFactory#ThreadListLoadingContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ThreadListLoadingContent(modifier: Modifier) {
        // Your implementation of the loading content
    }
}
```

<admonition type="note">

Overriding the `ThreadListLoadingContent` is the same as passing a custom
implementation for the `ThreadList#loadingContent` slot.

</admonition>

You can also customize the empty content of the thread list. You can do that by
overriding the `ChatComponentFactory#ThreadListEmptyContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

  @Composable
  override fun ThreadListEmptyContent(modifier: Modifier) {
    // Your implementation for the empty state
  }
}
```

<admonition type="note">

Overriding the `ThreadListEmptyContent` is the same as passing a custom
implementation for the `ThreadList#emptyContent` slot.

</admonition>

Finally, using the `ChatComponentFactory` you can also customize the loading
more indicator of the list, which is a loading indicator shown when a new page
of threads is being loaded. You can do that by overriding the
`ChatComponentFactory#ThreadListLoadingMoreContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun ThreadListLoadingMoreContent() {
      // Your implementation of the loading more indicator
    }
}
```

<admonition type="note">

Overriding the `ThreadListLoadingMoreContent` is the same as passing a custom
implementation for the `ThreadList#loadingMoreContent` slot.

</admonition>

### Pinned Message List

The `PinnedMessageList` component is used to display a list of all pinned
messages in a given channel (See
[Pinned Message List](/chat/docs/sdk/android/compose/guides/pinned-messages/)).

| Pinned messages list                                                              |
| --------------------------------------------------------------------------------- |
| ![PinnedMessagesList](../_assets/compose_default_pinned_message_list_content.jpg) |

As an alternative to using the composable slot parameters provided by the
`PinnedMessageList` component, you can also customize the appearance of the threads
via the `ChatComponentFactory`.

To customize the items in the pinned message list, you can override the
`ChatComponentFactory#PinnedMessageListItem` method. This method provides the
`Message` data which you can use to build your own implementation of the pinned
message item, and the `onClick` lambda which you can call when the item is
clicked:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun PinnedMessageListItem(
        message: Message,
        currentUser: User?,
        onClick: (Message) -> Unit,
    ) {
        // Your implementation of the pinned message list item
    }
}
```

<admonition type="note">

Overriding the `PinnedMessageListItem` is the same as passing a custom
implementation for the `PinnedMessageList#itemContent` slot.

</admonition>

Similar to other list items, the `ChatComponentFactory` provides a way for a
more granular customization of the pinned message list items. It provides
methods for customization of the:

- Loading content - Shows an avatar of the user who sent the pinned message.
- Center content - Shows the name of the sender, and a preview of the pinned
  message.
- Trailing content - Shows the timestamp when the message was sent.

To customize one or more of these parts of the pinned message list items, you
can override any of the corresponding methods:

- `PinnedMessageListItemLeadingContent`
- `PinnedMessageListItemCenterContent`
- `PinnedMessageListItemTrailingContent`

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun RowScope.PinnedMessageListItemLeadingContent(
        message: Message,
        currentUser: User?,
    ) {
        // Your implementation of the pinned message leading content
    }

    @Composable
    override fun RowScope.PinnedMessageListItemCenterContent(
        message: Message,
        currentUser: User?,
    ) {
        // Your implementation of the pinned message center content
    }

    @Composable
    override fun RowScope.PinnedMessageListItemTrailingContent(
        message: Message,
    ) {
        // Your implementation of the pinned message trailing content
    }
}
```

The `ChatComponentFactory` also provides a way for customizing the loading
content of the pinned message list. You can customize the default loading
indicator by overriding the
`ChatComponentFactory#PinnedMessageListLoadingContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun PinnedMessageListLoadingContent(modifier: Modifier) {
        // Your implementation of the loading content
    }
}
```

<admonition type="note">

Overriding the `PinnedMessageListLoadingContent` is the same as passing a
custom implementation for the `PinnedMessageList#loadingContent` slot.

</admonition>

You can also customize the empty content of the pinned message list. You can do
that by overriding the `ChatComponentFactory#PinnedMessageListEmptyContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

  @Composable
  override fun PinnedMessageListEmptyContent(modifier: Modifier) {
    // Your implementation for the empty state
  }
}
```

<admonition type="note">

Overriding the `PinnedMessageListEmptyContent` is the same as passing a custom
implementation for the `PinnedMessageList#emptyContent` slot.

</admonition>

Finally, using the `ChatComponentFactory` you can also customize the loading
more indicator of the list, which is a loading indicator shown when a new page
of pinned messages is being loaded. You can do that by overriding the
`ChatComponentFactory#PinnedMessageListLoadingMoreContent` method:

```kotlin
class CustomChatComponentFactory : ChatComponentFactory {

    @Composable
    override fun PinnedMessageListLoadingMoreContent() {
        // Your implementation of the loading more indicator
    }
}
```

<admonition type="note">

Overriding the `PinnedMessageListLoadingMoreContent` is the same as passing a
custom implementation for the `PinnedMessageList#loadingMoreContent` slot.

</admonition>

## Compound factory

You can also compose multiple factories together. This is useful when you want to customize
a specific UI component in the chain of your composable components, without overriding the entire
factories, for example:

```kotlin

ChatTheme(
    // Let's say you have a component factory which provides a custom implementation
    // for a few components, and you want to use it as a base factory.
    componentFactory = MyCustomChatComponentFactory()
) {
    // Given you have a big chain of composable components,
    // and you want to customize the message footer status indicator
    // only for a particular screen.

    // You can use LocalComponentFactory to get the current component factory.
    val currentComponentFactory = LocalComponentFactory.current

    // Then you create a new component factory,
    val myCustomMessageFooterStatusIndicator = remember {
        // Delegating the rest of the components to the current component factory,
        object : ChatComponentFactory by currentComponentFactory {
            // Overriding the specific component which you want to customize.
            @Composable
            override fun MessageFooterStatusIndicator(
                modifier: Modifier,
                message: Message,
                isMessageRead: Boolean,
                readCount: Int,
            ) {
                MyAwesomeMessageReadStatusIndicator()
            }
        }
    }
    // Finally, you can use a local composition to provide the new compound factory.
    CompositionLocalProvider(LocalComponentFactory provides myCustomMessageFooterStatusIndicator) {
        MessageList()
    }
}
```

## Scoped components

Compound factory is also useful when you want to reuse the default component implementation
but it is an extension of a scope, for example:

Let's say you want to wrap the default channel list item content in a box with a blue border:

```kotlin {14}
@Composable
override fun LazyItemScope.ChannelListItemContent(
  channelItem: ItemState.ChannelItemState,
  currentUser: User?,
  onChannelClick: (Channel) -> Unit,
  onChannelLongClick: (Channel) -> Unit,
) {
    Box(
        modifier = Modifier
            .background(color = Color.Blue)
            .padding(5.dp)
            .background(color = ChatTheme.colors.appBackground)
    ) {
        super.ChannelListItemContent( // ❌ It does not compile
            channelItem = channelItem,
            currentUser = currentUser,
            onChannelClick = onChannelClick,
            onChannelLongClick = onChannelLongClick
        )
    }
}
```

It doesn't compile because `ChannelListItemContent` is an extension of the `LazyItemScope`.

To achieve this, you need create a new factory which delegates the call to the original function
using the `with` operator:

```kotlin {13}
class CompoundComponentFactory(
    // Create a delegate which will be used to call the original function
    private val delegate: ChatComponentFactory = object : ChatComponentFactory {},
) : ChatComponentFactory by delegate {
    @Composable
    override fun LazyItemScope.ChannelListItemContent(
        channelItem: ItemState.ChannelItemState,
        currentUser: User?,
        onChannelClick: (Channel) -> Unit,
        onChannelLongClick: (Channel) -> Unit,
    ) {
        // Expose the scope from the delegate
        with(delegate) {
            // Wrap the original function in your custom UI
            Box(
                modifier = Modifier
                    .background(color = Color.Blue)
                    .padding(5.dp)
                    .background(color = ChatTheme.colors.appBackground)
            ) {
                // Call the original function
                ChannelListItemContent(
                    channelItem = channelItem,
                    currentUser = currentUser,
                    onChannelClick = onChannelClick,
                    onChannelLongClick = onChannelLongClick
                )
            }
        }
    }
}

```

## Summary

The `ChatComponentFactory` interface provides a powerful way to customize the
UI components of the Chat screens. By implementing this interface and
overriding the desired methods, developers can precisely customize specific
components, without the need to re-implement big parts of the composable UI.

---

This page was last updated at 2025-08-15T14:15:39.806Z.

For the most recent version of this documentation, visit [https://getstream.io/chat/docs/sdk/android/compose/general-customization/component-factory/](https://getstream.io/chat/docs/sdk/android/compose/general-customization/component-factory/).