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

# Message Composer

> Configure CometChat Flutter UI Kit Message Composer for text, media, custom messages, live reactions, editing, rich text, and audio.

<Accordion title="AI Integration Quick Reference">
  | Field | Value |
  | - | - |
  | Component | `CometChatMessageComposer` |
  | Package | `cometchat_chat_uikit` |
  | Import | `import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';` |
  | Purpose | Configure CometChat Flutter UI Kit Message Composer for text, media, custom messages, live reactions, editing, rich text, and audio. |
  | Data props | `user` · `group` · `parentMessageId` |
  | Actions | `onChange` · `onError` · `onSendButtonTap` · `onRichTextFormatApplied` · `onKeyboardDiagnostics` · `onAttachmentTrayAdd` · `onAttachmentTraySend` · `onAttachmentErrorTap` |
  | View slots | `auxiliaryButtonView` · `headerView` · `footerView` · `secondaryButtonView` · `richTextToolbarView` · `attachmentErrorSnackBarBuilder` |
  | Styling | `messageComposerStyle` — the app `ThemeData` does not reach inside a kit widget, so scope colours here. |
  | Sending outside the composer | A message sent with `CometChat.send*Message` instead of through this widget must emit `CometChatMessageEvents.ccMessageSent(...)` in `onSuccess`, or an already-mounted `CometChatMessageList` never shows it. |
  | Stitching | Pair with `CometChatMessageHeader` and `CometChatMessageList`, passing the same `user` or `group` to all three. |
  | Prerequisites | `CometChatUIKit` initialised and a user logged in. |
  | Full props | [73 props](#message-composer-properties) |
</Accordion>

## Overview

`CometChatMessageComposer` is a [Widget](/ui-kit/flutter/components-overview#widget) that enables users to write and send a variety of messages, including text, image, video, and custom messages.

Features such as **Live Reaction**, **Attachments**, **Message Editing**, **Rich Text Formatting**, **Code Blocks**, and **Inline Audio Recording** are supported.

`CometChatMessageComposer` is comprised of the following Base Widgets:

| Base Widgets | Description |
| - | - |
| MessageInput | Provides a basic layout for the contents, such as the TextField and buttons |
| ActionSheet | Presents a list of options in either a list or grid mode |

In V6, the composer is powered by `MessageComposerBloc` and decomposed into focused sub-widgets.

## Usage

### Integration

##### 1. Using Navigator to Launch `CometChatMessageComposer`

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    Navigator.push(context, MaterialPageRoute(builder: (context) => CometChatMessageComposer(user: user)));
    ```
  </Tab>
</Tabs>

##### 2. Embedding `CometChatMessageComposer` as a Widget in the build Method

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';
    import 'package:flutter/material.dart';

    class MessageComposerScreen extends StatefulWidget {
      const MessageComposerScreen({super.key});

      @override
      State<MessageComposerScreen> createState() => _MessageComposerScreenState();
    }

    class _MessageComposerScreenState extends State<MessageComposerScreen> {
      @override
      Widget build(BuildContext context) {
        return Scaffold(
          body: Column(
            children: [
              Expanded(child: CometChatMessageList(user: user)),
              CometChatMessageComposer(user: user),
            ],
          ),
        );
      }
    }
    ```
  </Tab>
</Tabs>

***

### Actions

##### 1. OnSendButtonClick

The `OnSendButtonClick` event gets activated when the send message button is clicked.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      onSendButtonTap: (BuildContext context, BaseMessage baseMessage, PreviewMessageMode? previewMessageMode) {
        // Handle send
      },
    )
    ```
  </Tab>
</Tabs>

***

##### 2. onChange

Handles changes in the value of text in the input field.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      onChange: (String? text) {
        // Handle text change
      },
    )
    ```
  </Tab>
</Tabs>

***

##### 3. onError

Listens for any errors that occur.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      onError: (e) {
        // Handle error
      },
    )
    ```
  </Tab>
</Tabs>

***

### Filters

`CometChatMessageComposer` widget does not have any available filters.

***

### Events

The `CometChatMessageComposer` Widget does not emit any events of its own.

***

## Customization

### Style

##### 1. CometChatMessageComposerStyle

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      messageComposerStyle: CometChatMessageComposerStyle(
        sendButtonIconBackgroundColor: Color(0xFFF76808),
        secondaryButtonIconColor: Color(0xFFF76808),
        auxiliaryButtonIconColor: Color(0xFFF76808),
      ),
    )
    ```
  </Tab>
</Tabs>

##### 2. MediaRecorder Style

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      messageComposerStyle: CometChatMessageComposerStyle(
        mediaRecorderStyle: CometChatMediaRecorderStyle(
          recordIndicatorBackgroundColor: Color(0xFFF44649),
          recordIndicatorBorderRadius: BorderRadius.circular(20),
        ),
      ),
    )
    ```
  </Tab>
</Tabs>

***

### Functionality

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      placeholderText: "Type a message...",
      disableMentions: true,
    )
    ```
  </Tab>
</Tabs>

## Message Composer Properties

| Property | Type | Default | Description |
| - | - | - | - |
| `user` | `User?` | `null` | Sets user for the message composer. |
| `group` | `Group?` | `null` | Sets group for the message composer. |
| `messageComposerStyle` | `CometChatMessageComposerStyle?` | `null` | Sets style for the message composer. |
| `placeholderText` | `String?` | `null` | Hint text for the input field. |
| `disableTypingEvents` | `bool` | `false` | Disables typing events. |
| `disableSoundForMessages` | `bool` | `false` | Disables sound for sent messages. |
| `parentMessageId` | `int` | `0` | ID of the parent message (default is 0). |
| `customSoundForMessage` | `String?` | `null` | `customSoundForMessage` provides custom sound for message sent |
| `customSoundForMessagePackage` | `String?` | `null` | `customSoundForMessagePackage` package name to show icon from |
| `auxiliaryButtonView` | `ComposerWidgetBuilder?` | `null` | UI component as auxiliary button. |
| `headerView` | `ComposerWidgetBuilder?` | `null` | `headerView` ui component to be forwarded to message input component |
| `footerView` | `ComposerWidgetBuilder?` | `null` | `footerView` ui component to be forwarded to message input component |
| `secondaryButtonView` | `ComposerWidgetBuilder?` | `null` | UI component as secondary button. |
| `sendButtonView` | `Widget?` | `null` | Custom send button widget. |
| `attachmentOptions` | `ComposerActionsBuilder?` | `null` | Provides options for file attachments. |
| `text` | `String?` | `null` | Initial text for the input field. |
| `onChange` | `Function(String text)?` | `null` | Callback triggered when text changes. |
| `maxLine` | `int?` | `null` | Maximum number of lines allowed. |
| `auxiliaryButtonsAlignment` | `AuxiliaryButtonsAlignment?` | `null` | `auxiliaryButtonsAlignment` controls position auxiliary button view |
| `attachmentIconURL` | `String?` | `null` | `attachmentIconURL` path of the icon to show in the attachments button |
| `stateCallBack` | `void Function(MessageComposerBloc bloc)?` | `null` | `stateCallBack` callback to handle state of the message composer Now returns MessageComposerBloc instead of the old controller |
| `attachmentIcon` | `Widget?` | `null` | Custom attachment icon. |
| `onError` | `OnError?` | `null` | Callback to handle errors. |
| `onSendButtonTap` | `Function( BuildContext context, BaseMessage message, PreviewMessageMode? previewMessageMode, )?` | `null` | Callback when send button is tapped. |
| `hideVoiceRecordingButton` | `bool?` | `null` | Hide the voice recording button. |
| `useInlineAudioRecorder` | `bool` | `true` | `useInlineAudioRecorder` when true, shows inline audio recorder in the composer instead of opening a bottom sheet. |
| `voiceRecordingIcon` | `Widget?` | `null` | Custom voice recording icon. |
| `aiIcon` | `Widget?` | `null` | `attachmentIcon` custom ai icon |
| `aiIconURL` | `String?` | `null` | `aiIconURL` path of the icon to show in the ai button |
| `aiIconPackageName` | `String?` | `null` | `aiIconPackageName` package name to show icon from |
| `textFormatters` | `List<CometChatTextFormatter>?` | `null` | `textFormatters` provides list of text formatters |
| `disableMentions` | `bool?` | `null` | Disables mentions in the composer. |
| `textEditingController` | `TextEditingController?` | `null` | Controls the state of the text field. |
| `padding` | `EdgeInsetsGeometry?` | `null` | `padding` provides padding to the message composer |
| `messageInputPadding` | `EdgeInsetsGeometry?` | `null` | `messageInputPadding` sets the padding to the message input field |
| `recorderStartButtonIcon` | `Widget?` | `null` | `recorderStartButtonIcon` defines the icon of the start button. |
| `recorderPauseButtonIcon` | `Widget?` | `null` | `recorderPauseButtonIcon` defines the icon of the pause button. |
| `recorderDeleteButtonIcon` | `Widget?` | `null` | `recorderDeleteButtonIcon` defines the icon of the delete button. |
| `recorderStopButtonIcon` | `Widget?` | `null` | `recorderStopButtonIcon` defines the icon of the stop button. |
| `recorderSendButtonIcon` | `Widget?` | `null` | `recorderSendButtonIcon` defines the icon of the send button. |
| `hideSendButton` | `bool?` | `null` | Hide/display the send button. |
| `hideAttachmentButton` | `bool?` | `null` | Hide/display attachment button. |
| `hideStickersButton` | `bool?` | `null` | Hide/display the sticker button. |
| `hideAudioAttachmentOption` | `bool?` | `null` | Hide/display audio attachment option. |
| `hideFileAttachmentOption` | `bool?` | `null` | Hide/display file attachment option. |
| `hideImageAttachmentOption` | `bool?` | `null` | Hide/display image attachment option. |
| `hideVideoAttachmentOption` | `bool?` | `null` | Hide/display video attachment option. |
| `hidePollsOption` | `bool?` | `null` | Hide/display polls option. |
| `hideCollaborativeDocumentOption` | `bool?` | `null` | `hideCollaborativeDocumentOption` is a `bool` that can be used to hide/display collaborative document option |
| `hideCollaborativeWhiteboardOption` | `bool?` | `null` | `hideCollaborativeWhiteboardOption` is a `bool` that can be used to hide/display collaborative whiteboard option |
| `hideTakePhotoOption` | `bool?` | `null` | `hideTakePhotoOption` is a `bool` that can be used to hide/display take photo option |
| `sendButtonIcon` | `Widget?` | `null` | Custom send button icon. |
| `disableMentionAll` | `bool` | `false` | `disableMentionAll` is a boolean which is used to disable @all mentions in groups |
| `mentionAllLabel` | `String?` | `null` | `mentionAllLabel` is a String which is used to set a custom label for @all mentions |
| `mentionAllLabelId` | `String?` | `null` | `mentionAllLabelId` is a String which is used to set a custom label ID for @all mentions |
| `enableRichTextFormatting` | `bool` | `true` | Master switch for rich text (markdown detection, toolbar, WYSIWYG rendering). Default `true`. |
| `showRichTextFormattingOptions` | `bool` | `true` | Whether the rich text toolbar UI is visible. Default `true`. |
| `hideRichTextFormattingOptions` | `Set<FormatType>` | `const {}` | Set of format buttons to hide from the toolbar. Default `{}`. |
| `richTextToolbarView` | `Widget Function(BuildContext context, TextEditingController controller)?` | `null` | Custom rich text toolbar widget. |
| `onRichTextFormatApplied` | `void Function(FormatType formatType)?` | `null` | Callback fired when a toolbar format is applied. |
| `hideBottomSafeArea` | `bool` | `false` | Hide bottom safe area padding (default: `false`). |
| `resizeToAvoidBottomInset` | `bool` | `true` | Indicates the parent `Scaffold` uses its default `resizeToAvoidBottomInset: true` and will handle keyboard insets itself. Default `true`. Flip to `false` only if you opt into the composer's internal keyboard-aware spacing and set `resizeToAvoidBottomInset: false` on your Scaffold. |
| `layout` | `CometChatComposerLayout` | `CometChatComposerLayout.singleLine` | Composer skeleton: `singleLine` (default) or `doubleLine`. See [Layout](#layout) below. |
| `onKeyboardDiagnostics` | `CometChatKeyboardDiagnosticsCallback?` | `null` | Debug hook fired on every internal keyboard-state change. Leave `null` in production. |
| `enableMultipleAttachments` | `bool` | `true` | `enableMultipleAttachments` when true (the default) the composer owns a multi-attachment staging tray: picked files upload immediately, stage as tray tiles, and send as one message per… |
| `attachmentTrayController` | `AttachmentTrayController?` | `null` | Optional external staging tray controller. |
| `onAttachmentTrayAdd` | `VoidCallback?` | `null` | Invoked by the tray's Add affordance when `attachmentTrayController` is set. |
| `onAttachmentTraySend` | `VoidCallback?` | `null` | Invoked by the tray's Send affordance (shown only when the tray can send). |
| `disableImagePaste` | `bool` | `false` | `disableImagePaste` disables staging an image pasted from the clipboard (context-menu Paste, Cmd/Ctrl+V, and the web paste event). |
| `disableDragAndDrop` | `bool` | `false` | `disableDragAndDrop` disables staging files dragged onto the chat and the "drop files here" overlay (web only). |
| `attachmentErrorAlertStyle` | `CometChatAttachmentErrorAlertStyle?` | `null` | `attachmentErrorAlertStyle` styles every attachment error alert: the toast shown when a selection is over the count/size limit, and the alert stating why a staged attachment was rejected… |
| `attachmentErrorSnackBarBuilder` | `SnackBar Function(BuildContext context, AttachmentTile tile)?` | `null` | `attachmentErrorSnackBarBuilder` fully replaces the default error snackbar. |
| `onAttachmentErrorTap` | `void Function(BuildContext context, AttachmentTile tile)?` | `null` | `onAttachmentErrorTap` fully overrides the tap/hover action on an errored tile (skips showing the default/custom snackbar entirely). |

***

### Advanced

#### TextFormatters

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      textFormatters: [
        CometChatMentionsFormatter(
          style: CometChatMentionsStyle(
            mentionSelfTextBackgroundColor: Color(0xFFF76808),
            mentionTextBackgroundColor: Colors.white,
            mentionTextColor: Colors.black,
            mentionSelfTextColor: Colors.white,
          ),
        ),
      ],
    )
    ```
  </Tab>
</Tabs>

***

#### AttachmentOptions

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      attachmentOptions: (context, user, group, id) {
        return <CometChatMessageComposerAction>[
          CometChatMessageComposerAction(
            id: "Custom Option",
            title: "Custom Option",
            icon: Icon(Icons.add_box, color: Colors.black),
          ),
        ];
      },
    )
    ```
  </Tab>
</Tabs>

***

#### AuxiliaryButton Widget

You can customize the auxiliary button area (mic, sticker, etc.) using the `auxiliaryButtonView` parameter:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      auxiliaryButtonView: (context, user, group, id) {
        return Row(
          children: [
            IconButton(
              icon: Icon(Icons.location_pin, color: Color(0xFF6852D6)),
              onPressed: () {
                // Handle location sharing
              },
            ),
          ],
        );
      },
    )
    ```
  </Tab>
</Tabs>

***

## Layout

The composer skeleton supports two layouts via the `layout` prop:

| Value | Description |
| - | - |
| `CometChatComposerLayout.singleLine` | **Default.** Text field and all buttons share a single row. |
| `CometChatComposerLayout.doubleLine` | Classic v5 look — text field on its own row, buttons on a second row below a divider. |

All existing props (hide flags, view slots, style, mentions, rich text, voice recording, reply/edit preview, AI options) work identically in both layouts.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      layout: CometChatComposerLayout.doubleLine,
    )
    ```
  </Tab>
</Tabs>

***

## Rich Text Formatting

The composer ships with a WYSIWYG rich-text toolbar that parses Markdown as the user types and renders formatted spans in place. Configuration is done with three flat props.

### Enable with defaults

Rich text is on by default — no props required.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(user: user)
    ```
  </Tab>
</Tabs>

### Show or hide the toolbar UI

`showRichTextFormattingOptions` controls toolbar visibility. When `false`, markdown is still parsed in typed text but no toolbar is rendered.

| Layout | Toolbar placement |
| - | - |
| `singleLine` | Persistent row directly below the text input |
| `doubleLine` | Behind an `Aa` toggle in the button row — tapping swaps in the toolbar |

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      showRichTextFormattingOptions: false, // parses markdown, no toolbar
    )
    ```
  </Tab>
</Tabs>

### Hide specific format buttons

Pass a `Set<FormatType>` listing the buttons to remove from the toolbar.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      hideRichTextFormattingOptions: const {
        FormatType.strikethrough,
        FormatType.codeBlock,
        FormatType.blockquote,
      },
    )
    ```
  </Tab>
</Tabs>

### Disable rich text entirely

Set `enableRichTextFormatting: false` to behave as a plain text field — no markdown parsing, no toolbar, regardless of the other two props.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      enableRichTextFormatting: false,
    )
    ```
  </Tab>
</Tabs>

### FormatType values

| Value | Markdown |
| - | - |
| `FormatType.bold` | `**text**` |
| `FormatType.italic` | `_text_` or `*text*` |
| `FormatType.underline` | `<u>text</u>` |
| `FormatType.strikethrough` | `~~text~~` |
| `FormatType.inlineCode` | `` `code` `` |
| `FormatType.codeBlock` | ` ```code``` ` |
| `FormatType.link` | `[text](url)` |
| `FormatType.bulletList` | `- item` |
| `FormatType.orderedList` | `1. item` |
| `FormatType.blockquote` | `> quote` |

### Custom toolbar view

`richTextToolbarView` receives the active controller. Because the controller is a `RichTextEditingController` under the hood, apply formats directly via `applyFormat`.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      richTextToolbarView: (context, controller) {
        return Row(
          children: [
            IconButton(
              icon: const Icon(Icons.format_bold),
              onPressed: () {
                (controller as RichTextEditingController).applyFormat(FormatType.bold);
              },
            ),
            IconButton(
              icon: const Icon(Icons.format_italic),
              onPressed: () {
                (controller as RichTextEditingController).applyFormat(FormatType.italic);
              },
            ),
          ],
        );
      },
      onRichTextFormatApplied: (formatType) {
        debugPrint('Applied ${formatType.name}');
      },
    )
    ```
  </Tab>
</Tabs>

***

## Multiple Attachments

The composer can stage several media/file attachments and send them as one message.

1. **Pick** — the image/video option opens a multi-select picker, capped to the slots left on the message. Audio and documents are multi-select too.
2. **Stage** — each pick lands in the **attachment tray** as a tile with a live progress ring, and starts uploading immediately.
3. **Send** — the send button stays disabled until every tile finishes. Text typed alongside rides along as the **caption**, with rich-text formatting preserved as Markdown.

Files can also arrive by **clipboard paste** (images, video, audio, documents) and, on web, by **drag-and-drop** onto the composer.

A selection spanning several kinds is split by kind and sent as one message per kind, in the order image → video → audio → file. Every message therefore carries a single kind and renders with that kind's bubble — pick three photos and a PDF and the photos still arrive as an image grid, the PDF as a file card. They share a `batchId`, so the [Message List](/ui-kit/flutter/message-list#multiple-attachments) groups them as one block.

<Note>
  Voice notes are never staged — a recording is always its own message and sends immediately. While the tray holds any tile, the mic button is hidden.
</Note>

### Limits and Validation

Limits come from your app's settings in the [CometChat dashboard](https://app.cometchat.com) and are read at runtime — the UI Kit does not hardcode them.

| Limit | Setting | Behaviour |
| - | - | - |
| Files per message | `file.count.max` (default 10) | The picker is capped to the remaining slots. A selection larger than that is rejected **whole**, with a toast — nothing is staged. |
| Per-file size | `file.size.max` (default 100 MB) | An over-sized file becomes a non-retryable error tile stating the limit. |
| File type | Server-side | Rejected uploads become error tiles. |

Error tiles come in two flavours and behave differently:

* **Failed** (network dropped) — tap the tile to **retry** it in place.
* **Rejected** (too large, wrong type, over the count) — not retryable; tapping explains why, and you remove the tile.

Sending is blocked while any tile is uploading **or** in error, so a caption can never go out while its attachments are still in flight.

### Disabling Multiple Attachments

Multiple attachments are on by default. Turn them off to restore the classic one-file-per-message behaviour.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      enableMultipleAttachments: false,
    )
    ```
  </Tab>
</Tabs>

<Warning>
  This is composer-side only. Incoming messages carrying several attachments still render as grouped bubbles — that is controlled by `enableMultipleAttachments` on [`CometChatMessageList`](/ui-kit/flutter/message-list#multiple-attachments).
</Warning>

### Styling the Attachment Tray

The staging tray's tiles are styled through the composer's own style object.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      messageComposerStyle: CometChatMessageComposerStyle(
        attachmentTrayStyle: CometChatAttachmentTrayStyle(),
      ),
    )
    ```
  </Tab>
</Tabs>

### Style the error alerts

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageComposer(
      user: user,
      // Styles the alert shown when a selection is over the count limit.
      attachmentErrorAlertStyle: CometChatAttachmentErrorAlertStyle(),
      // Replace the default error snackbar entirely.
      attachmentErrorSnackBarBuilder: (context, tile) => MySnackBar(tile),
      // Called when the user taps an error tile (skips the snackbar).
      onAttachmentErrorTap: (context, tile) {},
    )
    ```
  </Tab>
</Tabs>

### Multiple Attachments Properties

| Property | Data Type | Description |
| - | - | - |
| `enableMultipleAttachments` | `bool` | Master switch for staging. Defaults to `true`. |
| `attachmentTrayController` | `AttachmentTrayController?` | Drive the tray yourself. When omitted the composer owns one. |
| `onAttachmentTrayAdd` | `VoidCallback?` | Fires when the user taps **+** on the tray. |
| `onAttachmentTraySend` | `VoidCallback?` | Overrides the batch send — you send the messages yourself. |
| `disableImagePaste` | `bool` | Turns off clipboard paste. Defaults to `false`. |
| `disableDragAndDrop` | `bool` | Turns off drag-and-drop on web. Defaults to `false`. |
| `errorAlertStyle` | `CometChatErrorAlertStyle?` | Styles the over-limit toast. |
| `attachmentErrorSnackBarStyle` | `CometChatAttachmentErrorSnackBarStyle?` | Styles the error-tile snackbar. |
| `attachmentErrorSnackBarBuilder` | `Widget Function(BuildContext, AttachmentTile)?` | Replaces the error snackbar. |
| `onAttachmentErrorTap` | `Function(AttachmentTile)?` | Called when an error tile is tapped. |

For the upload API underneath the tray, see [Upload Files & Send Attachments](/sdk/flutter/upload-files).

***

## V6 Architecture

### Sub-Widget Decomposition

| Widget | Purpose |
| - | - |
| `AttachmentOptionsOverlay` | Attachment picker overlay |
| `MessageComposerAuxiliaryButtons` | Auxiliary button area |
| `MessageComposerSecondaryButtons` | Secondary button area |
| `MessageComposerSendButton` | Send button |
| `MessageComposerSuggestionList` | Suggestion/mention list |
| `ComposerAttachmentUtils` | Attachment utilities |

### BLoC Architecture

| Component | Description |
| - | - |
| `MessageComposerBloc` | Manages composer state |
| `MessageComposerEvent` | Events: `SendTextMessage`, `SendMediaMessage`, `EditTextMessage`, `StartTyping`, `EndTyping`, etc. |
| `MessageComposerState` | Composer state |

### Use Cases

| Use Case | Description |
| - | - |
| `SendTextMessageUseCase` | Sends text messages |
| `SendMediaMessageUseCase` | Sends media messages |
| `SendCustomMessageUseCase` | Sends custom messages |
| `EditMessageUseCase` | Edits messages |
| `TypingUseCases` | Start/end typing indicators |
| `GetLoggedInUserUseCase` | Gets the logged-in user |


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