> ## Documentation Index
> Fetch the complete documentation index at: https://cometchat-22654f5b-feature-android-multimedia-attachments.mintlify.site/llms.txt
> Use this file to discover all available pages before exploring further.

# Message Composer

> Message input area with send, attachment, voice note, sticker, and AI buttons. Supports text, media, mentions, and message editing.

`CometChatMessageComposer` renders the message input area and sends messages to the active conversation. It supports text, media, mentions, voice notes, stickers, and AI-powered features.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-android-multimedia-attachments/FTgXLQdPHe0aGzW9/images/8becc772-message_composer-0cc03defaf535f332f7f8bb1ebd65392.png?fit=max&auto=format&n=FTgXLQdPHe0aGzW9&q=85&s=5f9844e2225bb54e8ac3d10d1b975e48" width="2560" height="464" data-path="images/8becc772-message_composer-0cc03defaf535f332f7f8bb1ebd65392.png" />
</Frame>

***

## Where It Fits

`CometChatMessageComposer` is an input component. Wire it with `CometChatMessageHeader` and `CometChatMessageList` to build a complete messaging layout.

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```xml activity_chat.xml lines theme={null}
    <com.cometchat.uikit.kotlin.presentation.messagecomposer.ui.CometChatMessageComposer
        android:id="@+id/message_composer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    ```

    ```kotlin lines theme={null}
    val messageComposer = findViewById<CometChatMessageComposer>(R.id.message_composer)
    messageComposer.setUser(user)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user
    )
    ```
  </Tab>
</Tabs>

***

## Quick Start

<Tabs>
  <Tab title="Kotlin (XML Views)">
    Add to your layout XML:

    ```xml lines theme={null}
    <com.cometchat.uikit.kotlin.presentation.messagecomposer.ui.CometChatMessageComposer
        android:id="@+id/composer"
        android:layout_width="match_parent"
        android:layout_height="wrap_content" />
    ```

    Set a `User` or `Group`:

    ```kotlin lines theme={null}
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContentView(R.layout.your_layout)

        val composer = findViewById<CometChatMessageComposer>(R.id.composer)
        composer.setUser(user)
        // or composer.setGroup(group)
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    @Composable
    fun ComposerScreen() {
        CometChatMessageComposer(
            user = user
            // or group = group
        )
    }
    ```
  </Tab>
</Tabs>

Prerequisites: CometChat SDK initialized with `CometChatUIKit.init()`, a user logged in, and the UI Kit dependency added.

<Warning>
  The MessageComposer manages runtime permissions. To ensure the **ActivityResultLauncher** is properly initialized, create the composer in the **onCreate** state of an activity. If using a fragment, load it in the activity's `onCreate`.
</Warning>

***

## Actions and Events

### Callback Methods

#### `onSendButtonClick`

Fires when the send button is tapped. Override to intercept or replace the default message-sending logic.

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    messageComposer.setOnSendButtonClick { context, baseMessage ->
        // Custom send logic
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        onSendButtonClick = { context, baseMessage ->
            // Custom send logic
        }
    )
    ```
  </Tab>
</Tabs>

#### `onError`

Fires on internal errors (network failure, auth issue, SDK exception).

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    messageComposer.setOnError { context, exception ->
        Log.e("Composer", "Error: ${exception.message}")
    }
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        onError = { context, exception ->
            Log.e("Composer", "Error: ${exception.message}")
        }
    )
    ```
  </Tab>
</Tabs>

### SDK Events

The MessageComposer does not attach SDK listeners directly. Typing indicators are managed internally when `disableTypingEvents` is `false` (default).

***

## Functionality

| Method (Kotlin XML)                  | Compose Parameter                  | Description                                                                                                                                                                                     |
| ------------------------------------ | ---------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
| `setUser(user)`                      | `user = user`                      | Set target user for 1-on-1 conversations                                                                                                                                                        |
| `setGroup(group)`                    | `group = group`                    | Set target group for group conversations                                                                                                                                                        |
| `setOnSendButtonClick { }`           | `onSendButtonClick = { }`          | Override send button behavior                                                                                                                                                                   |
| `setParentMessageId(id)`             | `parentMessageId = id`             | Set parent message ID for threaded replies                                                                                                                                                      |
| `setTextFormatters(list)`            | `textFormatters = list`            | Custom text formatters (mentions, etc.)                                                                                                                                                         |
| `setEnableRichTextFormatting(true)`  | `enableRichTextFormatting = true`  | Enable rich text formatting                                                                                                                                                                     |
| `setEnableMultipleAttachments(true)` | `enableMultipleAttachments = true` | Multi-select attachment picking with a preview tray (default `true`); `false` reverts to legacy single-attachment, send-immediately behavior. See [Multiple Attachments](#multiple-attachments) |
| `setMaxAttachmentCount(count)`       | —                                  | Lower the per-message attachment cap below the server limit (can only tighten it, never raise it)                                                                                               |

***

## Multiple Attachments

The composer supports sending several attachments in one go. Tapping a media or file option opens a multi-select picker; the picks are staged in an **attachment tray** above the input box, upload immediately, and are sent together when the user taps send.

**How it works:**

* **Multi-select picking** — the photo/video picker and the document picker both allow selecting multiple items, capped to the app's per-message limit. Camera captures and picker audio stage into the same tray.
* **Attachment tray** — each staged file shows as a tile (thumbnail for media, chip for files/audio) with a live upload progress indicator, a ✕ to cancel or remove, and tap-to-retry on a transfer failure. The tray is only visible while at least one file is staged.
* **Upload before send** — files upload as soon as they are staged (via the SDK's upload-first flow); the send button stays disabled until every tile finishes uploading. Text typed in the composer becomes the **caption** of the batch, with rich text formatting preserved.
* **One message per attachment type** — a mixed pick is split into separate messages in a fixed order (images → videos → audios → files) that share a `batchId` and render as grouped bubbles in the message list.
* **Clipboard paste** — images, videos, documents, and audio copied to the clipboard can be pasted straight into the composer and stage into the tray.
* **Voice notes stay standalone** — a mic recording always sends immediately as its own message and is never staged. Audio chosen through the file picker, by contrast, stages as a file attachment.
* Editing a media message edits its **caption** only; the message's attachments are preserved.

### Limits and Validation

Limits are governed by the app's server settings (CometChat dashboard) — the composer reads them at runtime through the SDK. `setMaxAttachmentCount()` can only **tighten** the limit client-side, never raise it above the server value.

| Limit             | Setting                          | Behavior on violation                                                                                                                                |
| ----------------- | -------------------------------- | ---------------------------------------------------------------------------------------------------------------------------------------------------- |
| Files per message | `file.count.max` (default 10)    | Picker selection is capped; overflow picks are dropped and a `MAX_ATTACHMENTS_EXCEEDED` error is emitted ("You can attach up to N files at a time.") |
| Per-file size     | `file.size.max` (default 100 MB) | The file stages as a **rejected** (non-retryable) error tile; sending is blocked until it is removed                                                 |
| File type         | Server-side validation           | The upload is refused by the server and the file becomes a **rejected** error tile                                                                   |

Each tile carries an `AttachmentUploadStatus` (`UPLOADING`, `DONE`, `FAILED`, `REJECTED`, `CANCELLED`) mapped directly from the SDK's per-file upload callbacks, so the tray shows the right affordance — cancel while uploading, **retry** on a `FAILED` (transient) tile, **remove** on a `REJECTED` (non-retryable) tile. Errors surface through the composer ViewModel's `errorEvent`, which you can observe to show your own snack bar.

### Disabling Multiple Attachments

Set the flag to `false` to restore the legacy behavior — single-item pickers that send immediately with no tray:

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    messageComposer.setEnableMultipleAttachments(false)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        enableMultipleAttachments = false
    )
    ```
  </Tab>
</Tabs>

This is composer-side only: received multi-attachment messages still render with the grouped bubbles (see [Message List](/ui-kit/android/v6/message-list)).

### Styling the Attachment Tray (Compose)

In the Compose UI Kit the tray strip is themed through `CometChatAttachmentTrayStyle`:

```kotlin lines theme={null}
CometChatMessageComposer(
    user = user,
    attachmentTrayStyle = CometChatAttachmentTrayStyle.default().copy(
        backgroundColor = Color(0xFFFEEDE1),
        tileSpacing = 8.dp
    )
)
```

The individual staged-tile visuals and the per-type message bubbles are covered in [Message Bubble Styling](/ui-kit/android/v6/message-bubble-styling).

***

## Custom View Slots

### Header View

Custom view above the text input area.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-android-multimedia-attachments/YU-_573VUKGYrg6P/images/dbb04a8b-message_composer_header_view-11ddf1d50aa74a8868351007037451f9.png?fit=max&auto=format&n=YU-_573VUKGYrg6P&q=85&s=5feed14204b14d7b95d686163d41f205" width="1280" height="240" data-path="images/dbb04a8b-message_composer_header_view-11ddf1d50aa74a8868351007037451f9.png" />
</Frame>

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    val view = LayoutInflater.from(context).inflate(R.layout.custom_header_layout, null)
    messageComposer.setHeaderView(view)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        headerView = {
            Card(colors = CardDefaults.cardColors(containerColor = Color(0xFFEDEAFA))) {
                Row(Modifier.padding(8.dp), verticalAlignment = Alignment.CenterVertically) {
                    Icon(painterResource(R.drawable.ic_notes), "Notes")
                    Spacer(Modifier.width(4.dp))
                    Text("Notes")
                }
            }
        }
    )
    ```
  </Tab>
</Tabs>

### Send Button View

Replace the default send button.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-android-multimedia-attachments/YgamkpALQ8hAKN_V/images/3a7932a2-message_composer_send_button_view-f2e27a65301a5ced00e5854fa3b4ee6f.png?fit=max&auto=format&n=YgamkpALQ8hAKN_V&q=85&s=69bad03df68c93493bdba7b9cf5a84cc" width="1280" height="240" data-path="images/3a7932a2-message_composer_send_button_view-f2e27a65301a5ced00e5854fa3b4ee6f.png" />
</Frame>

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    val imageView = ImageView(this)
    imageView.setImageResource(R.drawable.custom_send_button)
    imageView.setOnClickListener {
        Toast.makeText(this, "Custom Send Button Clicked!", Toast.LENGTH_SHORT).show()
    }
    messageComposer.setSendButtonView(imageView)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        sendButtonView = {
            IconButton(onClick = { /* custom send */ }) {
                Icon(painterResource(R.drawable.custom_send_button), "Send")
            }
        }
    )
    ```
  </Tab>
</Tabs>

### Auxiliary Button View

Replace the auxiliary button area (stickers, AI).

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-android-multimedia-attachments/GncSMclyoFj1DgYn/images/673c7c47-message_composer_auxiliary_button_view-d7be5a9bcabce2d9260e8338658c8fc7.png?fit=max&auto=format&n=GncSMclyoFj1DgYn&q=85&s=b5aa4f0919aac6aad50215301018c38a" width="1280" height="240" data-path="images/673c7c47-message_composer_auxiliary_button_view-d7be5a9bcabce2d9260e8338658c8fc7.png" />
</Frame>

<Note>
  If you override the auxiliary button with `setAuxiliaryButtonView()`, retrieve the default auxiliary buttons via `CometChatUIKit.getDataSource().getAuxiliaryOption()` and include them in your custom layout to preserve sticker/AI buttons.
</Note>

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    val linearLayout = LinearLayout(this)
    linearLayout.orientation = LinearLayout.HORIZONTAL

    // Preserve default auxiliary buttons
    val defaultView = CometChatUIKit.getDataSource().getAuxiliaryOption(
        this, user, group,
        messageComposer.composerViewModel.getIdMap(),
        messageComposer.additionParameter
    )
    linearLayout.addView(defaultView)

    // Add custom button
    val customButton = ImageView(this)
    customButton.setImageResource(R.drawable.save_icon)
    linearLayout.addView(customButton)

    messageComposer.setAuxiliaryButtonView(linearLayout)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        auxiliaryButtonView = {
            Row {
                // Custom button alongside defaults
                IconButton(onClick = { /* action */ }) {
                    Icon(painterResource(R.drawable.save_icon), "Save")
                }
            }
        }
    )
    ```
  </Tab>
</Tabs>

### Attachment Options

Replace the default attachment options.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-android-multimedia-attachments/0xqWv6OXtYPSqnvx/images/927b388b-message_composer_attachment_options-7fab1d4e46f7ec14b998d555d3d26968.png?fit=max&auto=format&n=0xqWv6OXtYPSqnvx&q=85&s=1941340ad13b8deab046a20c47ee247b" width="1280" height="935" data-path="images/927b388b-message_composer_attachment_options-7fab1d4e46f7ec14b998d555d3d26968.png" />
</Frame>

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    val actionList = ArrayList<CometChatMessageComposerAction>()

    val action1 = CometChatMessageComposerAction()
    action1.title = "Custom Option 1"
    action1.icon = R.drawable.ic_cp_1
    action1.onClick = {
        Toast.makeText(context, "Custom Option 1", Toast.LENGTH_SHORT).show()
    }
    actionList.add(action1)

    messageComposer.setAttachmentOptions(actionList)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        attachmentOptions = listOf(
            CometChatMessageComposerAction(
                title = "Custom Option 1",
                icon = R.drawable.ic_cp_1,
                onClick = { /* handle */ }
            )
        )
    )
    ```
  </Tab>
</Tabs>

### Text Formatters (Mentions)

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-android-multimedia-attachments/I5qGE-j7-8uNC5q1/images/b2f00911-mentions_message_composer-b1d1dd7961bc3c2953e7439bb516200b.png?fit=max&auto=format&n=I5qGE-j7-8uNC5q1&q=85&s=f3e850c803805460bc7ec8ba2c193d7e" width="1280" height="800" data-path="images/b2f00911-mentions_message_composer-b1d1dd7961bc3c2953e7439bb516200b.png" />
</Frame>

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    val mentionFormatter = CometChatMentionsFormatter(context)
    mentionFormatter.setMessageComposerMentionTextStyle(context, R.style.CustomMentionsStyle)

    val textFormatters: MutableList<CometChatTextFormatter> = ArrayList()
    textFormatters.add(mentionFormatter)
    messageComposer.setTextFormatters(textFormatters)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    val mentionFormatter = CometChatMentionsFormatter(context)

    CometChatMessageComposer(
        user = user,
        textFormatters = listOf(mentionFormatter)
    )
    ```
  </Tab>
</Tabs>

***

## Style

<Tabs>
  <Tab title="Kotlin (XML Views)">
    Define a custom style in `themes.xml`:

    ```xml themes.xml lines theme={null}
    <style name="CustomMessageComposerStyle" parent="CometChatMessageComposerStyle">
        <item name="cometchatMessageComposerBackgroundColor">#FEEDE1</item>
        <item name="cometchatMessageComposerInputBackgroundColor">#FFFFFF</item>
    </style>

    <style name="AppTheme" parent="CometChatTheme.DayNight">
        <item name="cometchatMessageComposerStyle">@style/CustomMessageComposerStyle</item>
    </style>
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        style = CometChatMessageComposerStyle.default().copy(
            backgroundColor = Color(0xFFFEEDE1),
            inputBackgroundColor = Color.White
        )
    )
    ```
  </Tab>
</Tabs>

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-feature-android-multimedia-attachments/0IK7MlJ9Y4AvJ753/images/482915e0-message_composer_styling-db627f8855f376a0287e9d2d7f0be603.png?fit=max&auto=format&n=0IK7MlJ9Y4AvJ753&q=85&s=c02e4ed0d1d080f74ce84616004d3d86" width="1280" height="232" data-path="images/482915e0-message_composer_styling-db627f8855f376a0287e9d2d7f0be603.png" />
</Frame>

See [Component Styling](/ui-kit/android/v6/component-styling) for the full reference.

***

## ViewModel

```kotlin lines theme={null}
val viewModel = ViewModelProvider(this)
    .get(CometChatMessageComposerViewModel::class.java)
```

<Tabs>
  <Tab title="Kotlin (XML Views)">
    ```kotlin lines theme={null}
    messageComposer.setViewModel(viewModel)
    ```
  </Tab>

  <Tab title="Jetpack Compose">
    ```kotlin lines theme={null}
    CometChatMessageComposer(
        user = user,
        messageComposerViewModel = viewModel
    )
    ```
  </Tab>
</Tabs>

See [ViewModel & Data](/ui-kit/android/v6/customization-viewmodel-data) for state observation and custom repositories.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Message List" icon="messages" href="/ui-kit/android/v6/message-list">
    Display messages in a conversation
  </Card>

  <Card title="Message Header" icon="heading" href="/ui-kit/android/v6/message-header">
    Display user/group info in the toolbar
  </Card>

  <Card title="Message Template" icon="puzzle-piece" href="/ui-kit/android/v6/message-template">
    Customize message bubble structure
  </Card>

  <Card title="Component Styling" icon="paintbrush" href="/ui-kit/android/v6/component-styling">
    Detailed styling reference
  </Card>
</CardGroup>
