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

# Message Composer

> Configure CometChat iOS UI Kit Message Composer for text, media, attachments, mentions, voice notes, custom messages, and threads.

<Accordion title="AI Integration Quick Reference">
  ```json theme={null}
  {
    "component": "CometChatMessageComposer",
    "package": "CometChatUIKitSwift",
    "import": "import CometChatUIKitSwift\nimport CometChatSDK",
    "inherits": "UIView",
    "description": "Rich text input for composing and sending text, media, attachments, mentions, voice notes, and custom messages.",
    "props": {
      "data": {
        "user": "User? - recipient user for direct messaging",
        "group": "Group? - recipient group for group messaging",
        "parentMessageId": "Int? - parent message ID for thread replies"
      },
      "callbacks": {
        "onSendButtonClick": "(BaseMessage) -> Void",
        "onTextChangedListener": "(String) -> Void",
        "onError": "(CometChatException) -> Void"
      },
      "visibility": {
        "hideAttachmentButton": "Bool (default: false)",
        "hideVoiceRecordingButton": "Bool (default: false)",
        "hideStickersButton": "Bool (default: false)",
        "hideSendButton": "Bool (default: false)",
        "hideAIButton": "Bool (default: false)",
        "hideHeaderView": "Bool (default: false)",
        "hideFooterView": "Bool (default: false)"
      },
      "behavior": {
        "disableTypingEvents": "Bool (default: false)",
        "disableMentions": "Bool (default: false)",
        "enableMultipleAttachments": "Bool (default: true) - multi-select picker + attachment tray; false reverts to single-attachment send",
        "placeholderText": "String (default: 'Type a message...')"
      },
      "viewSlots": {
        "headerView": "(User?, Group?) -> UIView",
        "footerView": "(User?, Group?) -> UIView",
        "sendButtonView": "(User?, Group?) -> UIView",
        "auxillaryButtonView": "(User?, Group?) -> UIView",
        "attachmentOptions": "(User?, Group?, UIViewController?) -> [CometChatMessageComposerAction]"
      }
    },
    "methods": {
      "set(user:)": "Sets recipient user",
      "set(group:)": "Sets recipient group",
      "set(parentMessageId:)": "Sets parent message for threads",
      "setInitialComposerText(_:)": "Pre-fills composer text",
      "set(textFormatter:)": "Sets custom text formatter",
      "setDisableMentionAll(_:)": "Disables @all mentions",
      "setMentionAllLabel(_:_:)": "Customizes @all label"
    },
    "styling": {
      "globalStyle": "CometChatMessageComposer.style",
      "instanceStyle": "MessageComposerStyle",
      "subStyles": ["MediaRecorderStyle", "AttachmentSheetStyle", "SuggestionsStyle", "AIOptionsStyle", "MentionStyle"]
    }
  }
  ```
</Accordion>

| Field | Value |
| - | - |
| Component | `CometChatMessageComposer` |
| Package | `CometChatUIKitSwift` |
| Inherits | `UIView` |

The `CometChatMessageComposer` component enables users to write and send messages including text, images, videos, audio, files, and custom messages. It supports attachments, voice recording, stickers, mentions, and AI-powered features.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-agent-native-development/jALcxhGTlDP0cu9n/images/4d6dc597-h8F0Ugo204mAAAAABJRU5ErkJggg.png?fit=max&auto=format&n=jALcxhGTlDP0cu9n&q=85&s=354e7c98deb053f59dc2e7bc013a4c29" width="1280" height="232" data-path="images/4d6dc597-h8F0Ugo204mAAAAABJRU5ErkJggg.png" />
</Frame>

***

## Where It Fits

`CometChatMessageComposer` provides a rich text input with attachment, emoji, voice recording, sticker, and send controls. Wire it alongside `CometChatMessageHeader` and `CometChatMessageList` to build a standard chat view.

```swift lines theme={null}
import UIKit
import CometChatUIKitSwift
import CometChatSDK

class ChatViewController: UIViewController {
    
    override func viewDidLoad() {
        super.viewDidLoad()
        
        CometChat.getUser(UID: "uid") { user in
            DispatchQueue.main.async {
                let header = CometChatMessageHeader()
                header.set(user: user)
                
                let messageList = CometChatMessageList()
                messageList.set(user: user)
                
                let composer = CometChatMessageComposer()
                composer.set(user: user)
                
                // Add to view hierarchy and layout
            }
        } onError: { error in
            print("Error: \(error?.errorDescription ?? "")")
        }
    }
}
```

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-agent-native-development/jALcxhGTlDP0cu9n/images/4d6dc597-h8F0Ugo204mAAAAABJRU5ErkJggg.png?fit=max&auto=format&n=jALcxhGTlDP0cu9n&q=85&s=354e7c98deb053f59dc2e7bc013a4c29" width="1280" height="232" data-path="images/4d6dc597-h8F0Ugo204mAAAAABJRU5ErkJggg.png" />
</Frame>

***

## Minimal Render

```swift lines theme={null}
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)
```

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-agent-native-development/jALcxhGTlDP0cu9n/images/4d6dc597-h8F0Ugo204mAAAAABJRU5ErkJggg.png?fit=max&auto=format&n=jALcxhGTlDP0cu9n&q=85&s=354e7c98deb053f59dc2e7bc013a4c29" width="1280" height="232" data-path="images/4d6dc597-h8F0Ugo204mAAAAABJRU5ErkJggg.png" />
</Frame>

***

## Actions and Events

### Callback Props

#### onSendButtonClick

Fires when the send button is clicked. Overrides the default send behavior.

```swift lines theme={null}
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(onSendButtonClick: { message in
    print("Custom send: \(message.id)")
})
```

#### onTextChangedListener

Fires as the user types in the composer input.

```swift lines theme={null}
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(onTextChangedListener: { text in
    print("Text changed: \(text)")
})
```

#### onError

Fires on internal errors.

```swift lines theme={null}
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(onError: { error in
    print("Composer error: \(error.errorDescription)")
})
```

### SDK Events (Real-Time, Automatic)

The component internally handles typing indicators and message sending. No manual SDK listener attachment needed.

***

## Custom View Slots

| Slot | Signature | Replaces |
| - | - | - |
| `headerView` | `(User?, Group?) -> UIView` | Area above the composer input |
| `footerView` | `(User?, Group?) -> UIView` | Area below the composer input |
| `sendButtonView` | `(User?, Group?) -> UIView` | Send button |
| `auxillaryButtonView` | `(User?, Group?) -> UIView` | Sticker and AI button area |
| `attachmentOptions` | `(User?, Group?, UIViewController?) -> [CometChatMessageComposerAction]` | Default attachment options list |

### headerView

Custom view above the composer input.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-agent-native-development/BcLoqN2WGF-Pr9Oq/images/184d7b90-composerHeader-87fd3273b37867353fc6cb9ba041abcf.png?fit=max&auto=format&n=BcLoqN2WGF-Pr9Oq&q=85&s=89e420c8b7df0a6578e5aed86f423c82" width="1280" height="240" data-path="images/184d7b90-composerHeader-87fd3273b37867353fc6cb9ba041abcf.png" />
</Frame>

```swift lines theme={null}
import UIKit
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(headerView: { user, group in
    let view = UIView()
    view.backgroundColor = UIColor.purple.withAlphaComponent(0.1)
    
    let label = UILabel()
    label.text = "User has paused their notifications"
    label.font = UIFont.systemFont(ofSize: 14)
    view.addSubview(label)
    
    return view
})
```

### footerView

Custom view below the composer input.

```swift lines theme={null}
import UIKit
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(footerView: { user, group in
    let view = UIView()
    
    let label = UILabel()
    label.text = "Messages are end-to-end encrypted"
    label.font = UIFont.systemFont(ofSize: 12)
    label.textColor = .secondaryLabel
    view.addSubview(label)
    
    return view
})
```

### sendButtonView

Replace the send button.

```swift lines theme={null}
import UIKit
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(sendButtonView: { user, group in
    let button = UIButton(type: .system)
    button.setImage(UIImage(systemName: "paperplane.fill"), for: .normal)
    button.tintColor = .systemBlue
    return button
})
```

### auxillaryButtonView

Replace the sticker and AI button area.

```swift lines theme={null}
import UIKit
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(auxillaryButtonView: { user, group in
    let stackView = UIStackView()
    stackView.axis = .horizontal
    stackView.spacing = 8
    
    let aiButton = UIButton(type: .system)
    aiButton.setImage(UIImage(systemName: "sparkles"), for: .normal)
    
    let emojiButton = UIButton(type: .system)
    emojiButton.setImage(UIImage(systemName: "face.smiling"), for: .normal)
    
    stackView.addArrangedSubview(aiButton)
    stackView.addArrangedSubview(emojiButton)
    
    return stackView
})
```

### attachmentOptions

Override the default attachment options.

```swift lines theme={null}
import UIKit
import CometChatUIKitSwift

let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(attachmentOptions: { user, group, controller in
    return [
        CometChatMessageComposerAction(
            id: "photo",
            text: "Photo",
            startIcon: UIImage(systemName: "photo"),
            startIconTint: .systemBlue,
            onActionClick: { print("Photo selected") }
        ),
        CometChatMessageComposerAction(
            id: "camera",
            text: "Camera",
            startIcon: UIImage(systemName: "camera"),
            startIconTint: .systemGreen,
            onActionClick: { print("Camera selected") }
        ),
        CometChatMessageComposerAction(
            id: "location",
            text: "Location",
            startIcon: UIImage(systemName: "location"),
            startIconTint: .systemRed,
            onActionClick: { print("Location selected") }
        )
    ]
})
```

***

## 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.
* **Attachment tray** — each staged file shows as a tile (thumbnail for media, chip for files/audio) with a live upload progress ring, a ✕ to cancel or remove, and tap-to-retry on network failure.
* **Upload before send** — files upload as soon as they are staged; the send button stays disabled until every upload finishes. Text typed in the composer becomes the **caption** of the batch.
* **One message per attachment type** — a mixed pick is split into separate messages in a fixed order (images → videos → audios → files) that render as grouped bubbles in the message list.
* **Clipboard paste** — images, videos, documents and audio files 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.
* Attachments cannot be added while **editing** a message; the attachment button is disabled for the duration of the edit.

### Limits and Validation

Limits are governed by the app's server settings (CometChat dashboard) — the composer reads them at runtime and they cannot be overridden client-side:

| Limit | Setting | Behavior on violation |
| - | - | - |
| Files per message | `file.count.max` (default 10) | Picker selection is capped; overflow picks are dropped with a "You can attach up to N files." snack bar |
| Per-file size | `file.size.max` (default 100 MB) | The file stages as a red, 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 red, non-retryable error tile |

Tapping an error tile shows a snack bar with the reason ("File exceeds N MB.", "This file type isn't allowed."). The snack bar's appearance is themable through `CometChatErrorStateStyle`:

```swift theme={null}
CometChatErrorState.defaultStyle.backgroundColor = .systemRed
CometChatErrorState.defaultStyle.cornerRadius = 12
```

### Disabling Multiple Attachments

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

```swift theme={null}
composer.enableMultipleAttachments = false
```

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

***

## Common Patterns

### Thread composer

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.set(user: user)
composer.set(parentMessageId: parentMessage.id)
```

### Minimal composer — text only

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.set(user: user)
composer.hideAttachmentButton = true
composer.hideVoiceRecordingButton = true
composer.hideStickersButton = true
composer.hideAIButton = true
```

### Pre-filled text

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.set(user: user)
composer.setInitialComposerText("Hello! ")
composer.placeholderText = "Type a message..."
```

### Disable typing indicators

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.set(user: user)
composer.disableTypingEvents = true
```

### Disable mentions

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.set(user: user)
composer.disableMentions = true
```

### Custom send button action

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.set(user: user)

composer.set(onSendButtonClick: { message in
    print("Sending message: \(message)")
})
```

***

## Styling

### Style Hierarchy

1. Global styles (`CometChatMessageComposer.style`) apply to all instances
2. Instance styles override global for specific instances

### Global Level Styling

```swift lines theme={null}
import CometChatUIKitSwift

CometChatMessageComposer.style.backgroundColor = .systemBackground
CometChatMessageComposer.style.activeSendButtonImageBackgroundColor = .systemBlue
CometChatMessageComposer.style.attachmentImageTint = .systemGray
CometChatMessageComposer.style.voiceRecordingImageTint = .systemGray
```

### Instance Level Styling

```swift lines theme={null}
import CometChatUIKitSwift

var customStyle = MessageComposerStyle()
customStyle.backgroundColor = UIColor(red: 0.95, green: 0.95, blue: 0.97, alpha: 1.0)
customStyle.activeSendButtonImageBackgroundColor = .systemOrange
customStyle.composeBoxBackgroundColor = .white
customStyle.composeBoxBorderColor = .systemGray4

let composer = CometChatMessageComposer()
composer.style = customStyle
```

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-agent-native-development/pxaw3CU3ww5jOcRj/images/26eef3a8-composer-style-5a5323348b7b81745af3c1995036d6e7.png?fit=max&auto=format&n=pxaw3CU3ww5jOcRj&q=85&s=3200cc1c58b1788409d22bba921b942c" width="1280" height="232" data-path="images/26eef3a8-composer-style-5a5323348b7b81745af3c1995036d6e7.png" />
</Frame>

### Key Style Properties

| Property | Type | Description |
| - | - | - |
| `backgroundColor` | `UIColor` | Background color |
| `borderWidth` | `CGFloat` | Border width |
| `borderColor` | `UIColor` | Border color |
| `cornerRadius` | `CometChatCornerStyle?` | Corner radius |
| `placeHolderTextFont` | `UIFont` | Placeholder font |
| `placeHolderTextColor` | `UIColor` | Placeholder color |
| `textFiledColor` | `UIColor` | Input text color |
| `textFiledFont` | `UIFont` | Input text font |
| `sendButtonImage` | `UIImage?` | Send button icon |
| `sendButtonImageTint` | `UIColor` | Send button tint |
| `activeSendButtonImageBackgroundColor` | `UIColor` | Active send button background |
| `inactiveSendButtonImageBackgroundColor` | `UIColor` | Inactive send button background |
| `composeBoxBackgroundColor` | `UIColor` | Compose box background |
| `composeBoxBorderColor` | `UIColor` | Compose box border color |
| `composeBoxBorderWidth` | `CGFloat` | Compose box border width |
| `attachmentImage` | `UIImage?` | Attachment button icon |
| `attachmentImageTint` | `UIColor` | Attachment icon tint |
| `voiceRecordingImage` | `UIImage?` | Voice recording icon |
| `voiceRecordingImageTint` | `UIColor` | Voice recording tint |

### Sub-Component Styles

| Property | Type | Description |
| - | - | - |
| `mediaRecorderStyle` | `MediaRecorderStyle` | Voice recording interface |
| `attachmentSheetStyle` | `AttachmentSheetStyle` | Attachment options sheet |
| `suggestionsStyle` | `SuggestionsStyle` | Mentions suggestions view |
| `aiOptionsStyle` | `AIOptionsStyle` | AI options menu |
| `mentionStyle` | `MentionStyle` | Mentions appearance |

### Customization Matrix

| What to change | Where | Property/API |
| - | - | - |
| Override send behavior | Callback | `set(onSendButtonClick:)` |
| Track text input | Callback | `set(onTextChangedListener:)` |
| Toggle visibility | Props | `hide<Feature>` boolean props |
| Custom attachments | View Slot | `set(attachmentOptions:)` |
| Replace UI sections | View Slot | `set(headerView:)`, `set(sendButtonView:)` |
| Change colors, fonts | Style | `MessageComposerStyle` properties |

***

## Props

All props are optional. Sorted alphabetically.

| Property | Type | Default | Description |
| - | - | - | - |
| `disableMentions` | `Bool` | `false` | Disables the @mention feature |
| `disableSoundForMessages` | `Bool` | `false` | Disables sound when sending messages |
| `disableTypingEvents` | `Bool` | `false` | Disables sending typing indicators |
| `enableMultipleAttachments` | `Bool` | `true` | Multi-select attachment picking with a preview tray; `false` reverts to the legacy single-attachment, send-immediately behavior |
| `hideAIButton` | `Bool` | `false` | Hides the AI button |
| `hideAttachmentButton` | `Bool` | `false` | Hides the attachment button |
| `hideAudioAttachmentOption` | `Bool` | `false` | Hides the audio attachment option |
| `hideCollaborativeDocumentOption` | `Bool` | `false` | Hides the collaborative document option |
| `hideCollaborativeWhiteboardOption` | `Bool` | `false` | Hides the collaborative whiteboard option |
| `hideFileAttachmentOption` | `Bool` | `false` | Hides the file attachment option |
| `hideFooterView` | `Bool` | `false` | Hides the footer view |
| `hideHeaderView` | `Bool` | `false` | Hides the header view |
| `hideImageAttachmentOption` | `Bool` | `false` | Hides the image attachment option |
| `hidePollsOption` | `Bool` | `false` | Hides the polls option |
| `hideSendButton` | `Bool` | `false` | Hides the send button |
| `hideStickersButton` | `Bool` | `false` | Hides the stickers button |
| `hideVideoAttachmentOption` | `Bool` | `false` | Hides the video attachment option |
| `hideVoiceRecordingButton` | `Bool` | `false` | Hides the voice recording button |
| `maxLine` | `Int` | `5` | Maximum lines before scrolling |
| `placeholderText` | `String` | `"Type a message..."` | Placeholder text |
| `textFormatters` | `[CometChatTextFormatter]` | `[]` | Custom text formatters |

***

## Methods

### set(textFormatter:)

Sets a custom text formatter for the composer input.

```swift lines theme={null}
let composer = CometChatMessageComposer()
let mentionFormatter = MentionTextFormatter(trackingCharacter: "@")
composer.set(textFormatter: mentionFormatter)
```

### setDisableMentionAll(\_:)

Disables or enables the @all mention feature that notifies all group members.

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.setDisableMentionAll(true)
```

### setMentionAllLabel(*:*:)

Customizes the label displayed for @all mentions in the suggestions list.

```swift lines theme={null}
let composer = CometChatMessageComposer()
composer.setMentionAllLabel("Everyone", "Notify all members in this group")
```

***

## Related Components

* [Message List](/ui-kit/ios/message-list) — Display messages in a conversation
* [Message Header](/ui-kit/ios/message-header) — Display user/group details
* [Mentions Formatter](/ui-kit/ios/mentions-formatter-guide) — Configure @mention formatting


This documentation is built and hosted on [Mintlify](https://mintlify.com), a developer documentation platform.