> ## 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 List

> Scrollable list of messages for a conversation with real-time updates, reactions, threaded replies, and message actions.

<Accordion title="AI Integration Quick Reference">
  | Field | Value |
  | - | - |
  | Component | `CometChatMessageList` |
  | Package | `cometchat_chat_uikit` |
  | Import | `import 'package:cometchat_chat_uikit/cometchat_chat_uikit.dart';` |
  | Purpose | Scrollable list of messages for a conversation with real-time updates, reactions, threaded replies, and message actions. |
  | Data props | `user` · `group` · `messagesRequestBuilder` · `templates` · `addTemplate` · `parentMessageId` · `reactionsRequestBuilder` |
  | Actions | `onError` · `onLoad` · `onEmpty` · `onThreadRepliesClick` · `addMoreReactionTap` · `onReactionClick` · `onReactionLongPress` · `onReactionListItemClick` — [details](#actions-and-events) |
  | View slots | `headerView` · `footerView` · `loadingStateView` · `emptyStateView` · `errorStateView` · `emptyChatGreetingView` — [details](#custom-view-slots) |
  | Styling | `style` — the app `ThemeData` does not reach inside a kit widget, so scope colours here. |
  | Layout | Fills its parent — place it in an `Expanded` (or a sized box) inside a `Column`, or layout throws an unbounded-height error at render. |
  | Custom message types | Use `addTemplate:` — **never** `templates:`. `addTemplate` merges your `CometChatMessageTemplate` with the defaults **and** folds its type/category into the list's fetch + realtime filter; `templates` replaces the default set and only registers the bubble, so a custom type sends fine and **never appears**, with no error. A hand-rolled `MessagesRequestBuilder` does not help — the list always overrides `uid`/`guid`/`types`/`categories` on it. |
  | Stitching | Pair with `CometChatMessageHeader` and `CometChatMessageComposer`, passing the same `user` or `group` to all three. |
  | Prerequisites | `CometChatUIKit` initialised and a user logged in. |
  | Full props | [88 props](#functionality) |
</Accordion>

`CometChatMessageList` renders a scrollable list of messages for a conversation with real-time updates for new messages, edits, deletions, reactions, and threaded replies.

***

## Where It Fits

`CometChatMessageList` is a message display component. It requires either a `User` or `Group` object to fetch and render messages. Wire it with `CometChatMessageHeader` and `CometChatMessageComposer` to build a complete messaging layout.

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

***

## Quick Start

Using Navigator:

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

Embedding as a widget:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    @override
    Widget build(BuildContext context) {
      return Scaffold(
        body: SafeArea(
          child: CometChatMessageList(
            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>
  Simply adding the `MessageList` component to the layout will only display the loading indicator. You must supply a `User` or `Group` object to fetch messages.
</Warning>

***

## Filtering

Pass a `MessagesRequestBuilder` to control what loads:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      messagesRequestBuilder: MessagesRequestBuilder()
        ..uid = user.uid
        ..searchKeyword = "hello"
        ..limit = 30,
    )
    ```
  </Tab>
</Tabs>

<Note>
  The following parameters in `MessagesRequestBuilder` will always be altered inside the message list: UID, GUID, types, categories.
</Note>

***

## Actions and Events

### Callback Methods

#### `onThreadRepliesClick`

Fires when a user taps a threaded message bubble.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      onThreadRepliesClick: (message, context, {template}) {
        // Navigate to thread view
      },
    )
    ```
  </Tab>
</Tabs>

#### `onError`

Fires on internal errors.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      onError: (e) {
        debugPrint("Error: $e");
      },
    )
    ```
  </Tab>
</Tabs>

#### `onLoad`

Fires when the list is successfully fetched and loaded.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      onLoad: (messages) {
        debugPrint("Loaded ${messages.length}");
      },
    )
    ```
  </Tab>
</Tabs>

#### `onEmpty`

Fires when the list is empty after loading.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      onEmpty: () {
        debugPrint("No messages");
      },
    )
    ```
  </Tab>
</Tabs>

#### `onReactionClick`

Fires when a reaction pill is tapped.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      onReactionClick: (emoji, message) {
        // Handle reaction click
      },
    )
    ```
  </Tab>
</Tabs>

#### `onReactionLongPress`

Fires when a reaction pill is long-pressed.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      onReactionLongPress: (emoji, message) {
        // Handle reaction long press
      },
    )
    ```
  </Tab>
</Tabs>

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

The component listens to SDK message events internally. No manual setup needed.

| SDK Listener | Internal behavior |
| - | - |
| `onTextMessageReceived` / `onMediaMessageReceived` / `onCustomMessageReceived` | Inserts new message with animation |
| `onMessageEdited` | Updates message in-place |
| `onMessageDeleted` | Removes or marks message as deleted |
| `onMessagesDelivered` / `onMessagesRead` | Updates receipt status via ValueNotifier |
| `onTypingStarted` / `onTypingEnded` | Updates typing indicator |
| `onMessageReactionAdded` / `onMessageReactionRemoved` | Updates reaction counts |
| Connection reconnected | Triggers silent sync to fetch missed messages |

***

## Functionality

| Property | Type | Default | Description |
| - | - | - | - |
| `user` | `User?` | `null` | User for 1-on-1 conversation |
| `group` | `Group?` | `null` | Group for group conversation |
| `messageListBloc` | `MessageListBloc?` | `null` | Optional external `MessageListBloc` instance. |
| `messagesRequestBuilder` | `MessagesRequestBuilder?` | `null` | Request builder used to fetch the message list. Note the widget always overrides `uid`, `guid`, `types` and `categories` on whatever builder you pass. |
| `templates` | `List<CometChatMessageTemplate>?` | `null` | REPLACES the default message templates. For a message type of your own use `addTemplate` instead — `templates` only registers the bubble and does not widen the fetch filter, so a custom type sends successfully and never appears. |
| `addTemplate` | `List<CometChatMessageTemplate>?` | `null` | Merges templates with the defaults. Each template's type and category are also folded into the list's fetch and realtime filter, which is what makes a custom message type actually render. |
| `parentMessageId` | `int?` | `null` | Parent message ID for thread replies |
| `withParent` | `bool` | `true` | Whether to include the parent message in thread results (default: false). Set to true for AI chat history where the parent message should appear in the list. |
| `hideDeletedMessages` | `bool` | `false` | Hide deleted messages entirely |
| `disableSoundForMessages` | `bool` | `false` | Disable message sounds |
| `disableReceipts` | `bool` | `false` | Disable read/delivery receipts |
| `hideReplies` | `bool` | `true` | Hide thread replies in main conversation |
| `headerView` | `HeaderFooterBuilder?` | `null` | Custom header view displayed above the message list. **Validates: Requirements 13.2** |
| `footerView` | `HeaderFooterBuilder?` | `null` | Custom footer view displayed below the message list. **Validates: Requirements 13.2** |
| `loadingStateView` | `WidgetBuilder?` | `null` | `loadingStateView` is a parameter used to show the loading state view in case of loading |
| `emptyStateView` | `WidgetBuilder?` | `null` | `emptyStateView` returns view fow empty state |
| `errorStateView` | `WidgetBuilder?` | `null` | `errorStateView` is a parameter used to show the error state view in case of any error |
| `emptyChatGreetingView` | `WidgetBuilder?` | `null` | View shown in an empty conversation, in place of the generic empty state. |
| `style` | `CometChatMessageListStyle?` | `null` | Style configuration for the message list. |
| `scrollController` | `ScrollController?` | `null` | Optional scroll controller |
| `alignment` | `ChatAlignment` | `ChatAlignment.standard` | Chat alignment setting |
| `onError` | `OnError?` | `null` | `onError` callback triggered in case any error happens when fetching data |
| `onLoad` | `OnLoad<BaseMessage>?` | `null` | Called once the first page of messages has loaded. |
| `onEmpty` | `OnEmpty?` | `null` | `onEmpty` callback triggered when the list is empty |
| `stateCallBack` | `Function(CometChatMessageListControllerProtocol controller)?` | `null` | Exposes the widget's state so a host can drive it imperatively. |
| `customSoundForMessages` | `String?` | `null` | `customSoundForMessages` set custom sound for messages |
| `customSoundForMessagePackage` | `String?` | `null` | `customSoundForMessagePackage` package name to show icon from |
| `readIcon` | `Widget?` | `null` | `readIcon` widget visible when readAt != null in `BaseMessage`. If blank will load default readIcon |
| `deliveredIcon` | `Widget?` | `null` | `deliveredIcon` widget visible while deliveredAt != null in `BaseMessage`. If blank will load default deliveredIcon |
| `sentIcon` | `Widget?` | `null` | `sentIcon` widget visible while sentAt != null and deliveredAt is null in `BaseMessage`. If blank will load default sentIcon |
| `waitIcon` | `Widget?` | `null` | `waitIcon` widget visible while sentAt and deliveredAt is null in `BaseMessage`. If blank will load default waitIcon |
| `avatarVisibility` | `bool?` | `true` | Toggle avatar visibility |
| `enableMultipleAttachments` | `bool` | `true` | Render multi-attachment media messages as grouped per-type bubbles. See [Multiple Attachments](#multiple-attachments) |
| `hideTimestamp` | `bool?` | `null` | Toggle timestamp visibility |
| `datePattern` | `String Function(BaseMessage message)?` | `null` | Builds the timestamp string shown on a bubble. |
| `dateSeparatorPattern` | `String Function(DateTime dateTime)?` | `null` | Builds the date string shown on the separator between days. |
| `dateSeparatorStyle` | `CometChatDateStyle?` | `null` | Style for the date separator shown between days. |
| `hideDateSeparator` | `bool?` | `false` | Hide date separators |
| `hideStickyDate` | `bool?` | `false` | Hide floating sticky date header |
| `onThreadRepliesClick` | `ThreadRepliesClick?` | `null` | Called when the thread-replies indicator on a bubble is tapped. Wire this to push your thread screen. |
| `hideThreadView` | `bool?` | `null` | When true, hides the thread-replies indicator on bubbles. |
| `receiptsVisibility` | `bool?` | `true` | Toggle read receipts |
| `disableReactions` | `bool?` | `false` | Toggle reactions |
| `addReactionIcon` | `Widget?` | `null` | `addReactionIcon` sets custom icon for adding reaction |
| `addMoreReactionTap` | `Function(BaseMessage message)?` | `null` | Called when the 'add reaction' affordance is tapped. |
| `favoriteReactions` | `List<String>?` | `null` | `favoriteReactions` is a list of frequently used reactions |
| `onReactionClick` | `Function(String? emoji, BaseMessage message)?` | `null` | Called when an existing reaction chip is tapped. |
| `onReactionLongPress` | `Function(String? emoji, BaseMessage message)?` | `null` | Called when an existing reaction chip is long-pressed. |
| `onReactionListItemClick` | `Function(String? reaction, BaseMessage? message)?` | `null` | Called when a row in the reaction list sheet is tapped. |
| `reactionsRequestBuilder` | `ReactionsRequestBuilder?` | `null` | Request builder used to fetch the reaction list for a message. |
| `textFormatters` | `List<CometChatTextFormatter>?` | `null` | `textFormatters` is a list of `CometChatTextFormatter` that can be used to format text |
| `additionalConfigurations` | `AdditionalConfigurations?` | `null` | Configuration passed down to the bubble views this list renders. |
| `disableMentions` | `bool?` | `null` | `disableMentions` disables mentions in the composer |
| `mentionAllLabel` | `String?` | `null` | `mentionAllLabel` is the label to display for @all mention (default: localized "Notify All") |
| `mentionAllLabelId` | `String?` | `null` | `mentionAllLabelId` is the ID for @all mention (default: "all") |
| `padding` | `EdgeInsetsGeometry?` | `null` | `padding` sets the padding for snackBar |
| `margin` | `EdgeInsetsGeometry?` | `null` | `margin` sets the margin for snackBar |
| `width` | `double?` | `null` | `width` provides width to the widget |
| `height` | `double?` | `null` | `height` provides height to the widget |
| `hideCopyMessageOption` | `bool?` | `false` | `hideCopyMessageOption` This prop defines whether a user can copy message or not. |
| `hideDeleteMessageOption` | `bool?` | `false` | `hideDeleteMessageOption` This prop defines whether Delete Message option should be visible or not. |
| `hideEditMessageOption` | `bool?` | `false` | `hideEditMessageOption` This prop defines whether Edit Message option should be visible or not. |
| `hideGroupActionMessages` | `bool?` | `false` | Hide group action messages |
| `hideMessageInfoOption` | `bool?` | `false` | `hideMessageInfoOption` This prop defines whether a user can fetch information about the message whether it's received or not. |
| `hideMessagePrivatelyOption` | `bool?` | `false` | `hideMessagePrivatelyOption` This prop defines whether a user can privately message other member of the group or not. |
| `hideReactionOption` | `bool?` | `false` | `hideReactionOption` This prop defines whether Reaction option should be visible or not. |
| `hideReplyInThreadOption` | `bool?` | `false` | `hideReplyInThreadOption` This prop defines whether Reply In Thread option should be visible or not. |
| `hideReplyOption` | `bool?` | `false` | `hideReplyOption` This prop defines whether the inline Reply option should be visible or not. |
| `hideTranslateMessageOption` | `bool?` | `false` | `hideTranslateMessageOption` This prop defines whether Reply In Thread option should be visible or not. |
| `hideShareMessageOption` | `bool?` | `false` | `hideShareMessageOption` This prop defines whether share option should be visible or not. |
| `hideModerationView` | `bool?` | `null` | When true, hides the moderation affordance on bubbles. |
| `enableConversationStarters` | `bool?` | `false` | When true, shows AI conversation starters in an empty conversation. |
| `enableSmartReplies` | `bool?` | `false` | When true, shows AI smart replies beneath the list. |
| `smartRepliesDelayDuration` | `int?` | `10000` | Milliseconds to wait after the last message before smart replies appear. |
| `smartRepliesKeywords` | `List<String>?` | `const [ 'what', 'when', 'why', 'who', '…` | Keywords in the last message that trigger smart replies. |
| `suggestedMessages` | `List<String>?` | `null` | Suggested messages offered in an empty conversation. |
| `hideSuggestedMessages` | `bool?` | `false` | When true, suppresses the suggested messages. |
| `emptyStateText` | `String?` | `null` | `emptyStateText` text to be displayed when the list is empty |
| `errorStateText` | `String?` | `null` | `errorStateText` is a parameter used to show the error state text in case of any error |
| `dateTimeFormatterCallback` | `DateTimeFormatterCallback?` | `null` | `dateTimeFormatterCallback` is a callback that can be used to format the date and time |
| `enableSwipeToReply` | `bool` | `true` | Enable swipe-to-reply gesture |
| `goToMessageId` | `int?` | `null` | Scroll to a specific message after load |
| `showMarkAsUnreadOption` | `bool` | `false` | Show "Mark as Unread" in long-press options |
| `startFromUnreadMessages` | `bool` | `false` | Scroll to first unread on open |
| `hideFlagOption` | `bool` | `false` | Hide the Flag/Report option from message long-press actions |
| `flagReasonLocalizer` | `String Function(String reasonId)?` | `null` | Custom localizer that converts a flag-reason ID into a display string |
| `hideFlagRemarkField` | `bool` | `false` | Hide the optional remark/context text field in the flag dialog |
| `loadLastAgentConversation` | `bool` | `false` | Loads the most recent existing agent conversation on start |

\* One of `user` or `group` is required.

***

## Custom View Slots

### Header View

Custom view displayed at the top of the message list.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      headerView: (context, {user, group, parentMessageId}) {
        return Container(
          padding: EdgeInsets.all(8),
          child: Text("Pinned Messages"),
        );
      },
    )
    ```
  </Tab>
</Tabs>

### Footer View

Custom view displayed at the bottom of the message list.

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      footerView: (context, {user, group, parentMessageId}) {
        return Container(
          padding: EdgeInsets.all(8),
          child: Text("End of messages"),
        );
      },
    )
    ```
  </Tab>
</Tabs>

### State Views

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      emptyStateView: (context) => Center(child: Text("No messages yet")),
      errorStateView: (context) => Center(child: Text("Something went wrong")),
      loadingStateView: (context) => Center(child: CircularProgressIndicator()),
      emptyChatGreetingView: (context) => Center(child: Text("Say hello!")),
    )
    ```
  </Tab>
</Tabs>

### Text Formatters (Mentions)

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      textFormatters: [
        CometChatMentionsFormatter(),
      ],
    )
    ```
  </Tab>
</Tabs>

### Message Templates

Override or extend message bubble rendering:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    // Replace all templates
    CometChatMessageList(
      user: user,
      templates: getCustomTemplates(),
    )

    // Add/override specific templates (merged with defaults)
    CometChatMessageList(
      user: user,
      addTemplate: [
        CometChatMessageTemplate(
          type: MessageTypeConstants.text,
          category: MessageCategoryConstants.message,
          contentView: (message, context, alignment, {additionalConfigurations}) {
            return Text((message as TextMessage).text,
              style: TextStyle(color: Colors.red));
          },
        ),
      ],
    )
    ```
  </Tab>
</Tabs>

See [Message Template](/ui-kit/flutter/message-template) for the full template structure.

***

## Multiple Attachments

A media message carrying several attachments renders with a dedicated per-type bubble: a **media grid** for images and videos, **inline player rows** for audio files, and a **connected card stack** for documents.

| Message type | Bubble | Rendering |
| - | - | - |
| `image` | `CometChatImagesBubble` | Grid — 1, 2, 3 or 2×2, with a `+N` tile past 4 |
| `video` | `CometChatVideosBubble` | Grid with poster frames, a play badge and an `m:ss` chip |
| `audio` (files) | `CometChatAudiosBubble` | Stacked player rows; collapses past 4 |
| `audio` (voice note) | `CometChatAudioBubble` | The classic waveform player |
| `file` | `CometChatFilesBubble` | Connected card stack with a "+N more" toggle |

Tapping any image/video cell opens the full-screen media viewer, paged across the message's image, video and audio attachments.

<Note>
  A **voice note** always renders as the classic single audio bubble, whatever the flag below — it is single by nature. Only picked audio *files* use the multi-attachment bubble.
</Note>

A message always carries attachments of a single kind, so each one renders with the bubble for that kind. Picking a mix — say three photos and a PDF — sends an `image` message and a `file` message: the photos render as a grid, the PDF as a card. They share a `batchId` and group as described below.

### Grouping

Messages produced by one send share `batchId`, `batchIndex` and `batchSize` metadata, and the list presents them as one block:

* the avatar and sender name appear on the **first** message only
* the timestamp and receipt appear on the **last** message only
* reactions stay attached to their individual message
* the caption rides on the **last** message of the batch

Deleting one message of a batch takes it out of the group: it renders as a standalone delete bubble, and its neighbours treat it as a batch boundary.

### Enable or disable

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

Set it to `false` to render the classic single-attachment bubbles (`CometChatImageBubble`, `CometChatVideoBubble`, `CometChatAudioBubble`, `CometChatFileBubble`) instead. Those bubbles are **deprecated** and remain only for that path.

You can also drive it per-template through `AdditionalConfigurations`:

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

### Styling

Each bubble has its own style class:

| Bubble | Style |
| - | - |
| `CometChatImagesBubble` | `CometChatImagesBubbleStyle` |
| `CometChatVideosBubble` | `CometChatVideosBubbleStyle` |
| `CometChatAudiosBubble` | `CometChatAudiosBubbleStyle` |
| `CometChatFilesBubble` | `CometChatFilesBubbleStyle` |

Where a property has an equivalent on the old singular bubble it keeps the same name (`playIconColor`, `titleTextStyle`, `backgroundColor`…), so migrating is a rename of the class, not of every field. Grid-only knobs — `tileBorderRadius`, `gridSpacing`, `overflowScrimColor`, `captionTextStyle`, the duration chip and the "+N more" toggle — have no old counterpart.

<Warning>
  These bubbles are styled **only** through theme extensions. The per-message-list slots — `AdditionalConfigurations.imageBubbleStyle` and `CometChatIncoming/OutgoingMessageBubbleStyle.imageBubbleStyle` — still target the **deprecated** singular bubbles and are ignored while `enableMultipleAttachments` is `true`. Move that styling into the theme.
</Warning>

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    MaterialApp(
      theme: ThemeData(
        extensions: const [
          CometChatImagesBubbleStyle(gridSpacing: 3, tileBorderRadius: 8),
          CometChatVideosBubbleStyle(showVideoDuration: true),
          CometChatFilesBubbleStyle(titleTextStyle: TextStyle(fontSize: 15)),
        ],
      ),
    )
    ```
  </Tab>
</Tabs>

To stage and send multiple attachments, see [Message Composer](/ui-kit/flutter/message-composer#multiple-attachments).

***

## Message Option Visibility

| Property | Default | Description |
| - | - | - |
| `hideCopyMessageOption` | `false` | Hide "Copy Message" |
| `hideDeleteMessageOption` | `false` | Hide "Delete Message" |
| `hideEditMessageOption` | `false` | Hide "Edit Message" |
| `hideMessageInfoOption` | `false` | Hide "Message Info" |
| `hideMessagePrivatelyOption` | `false` | Hide "Message Privately" |
| `hideReactionOption` | `false` | Hide "Reaction" |
| `hideReplyInThreadOption` | `false` | Hide "Reply in Thread" |
| `hideTranslateMessageOption` | `false` | Hide "Translate Message" |
| `hideShareMessageOption` | `false` | Hide "Share Message" |
| `hideModerationView` | `null` | Hide moderation view |

***

## Common Patterns

### Thread replies view

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      parentMessageId: parentMessage.id,
    )
    ```
  </Tab>
</Tabs>

### Jump to a specific message

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      goToMessageId: 12345,
    )
    ```
  </Tab>
</Tabs>

### Start from unread messages

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      startFromUnreadMessages: true,
    )
    ```
  </Tab>
</Tabs>

### Load last agent conversation

Resume the most recent AI agent conversation on start:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      loadLastAgentConversation: true,
    )
    ```
  </Tab>
</Tabs>

### Flag / Report a message

Flag/report is available by default from the message long-press menu. Toggle its visibility and customize the dialog:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      // hide the Flag option entirely
      hideFlagOption: false,
      // hide the optional "Remark" text field in the flag dialog
      hideFlagRemarkField: false,
      // localize reason IDs to your own display strings
      flagReasonLocalizer: (reasonId) {
        switch (reasonId) {
          case 'spam':
            return 'Spam or unsolicited';
          case 'inappropriate':
            return 'Inappropriate content';
          default:
            return reasonId;
        }
      },
    )
    ```
  </Tab>
</Tabs>

### Mark a message as unread

Expose the "Mark as Unread" option in the long-press menu:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      showMarkAsUnreadOption: true,
    )
    ```
  </Tab>
</Tabs>

***

## Advanced

### BLoC Access

Provide a custom `MessageListBloc` to override behavior:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      messageListBloc: CustomMessageListBloc(user: user),
    )
    ```
  </Tab>
</Tabs>

### Extending MessageListBloc

`MessageListBloc` uses the `ListBase<BaseMessage>` mixin with override hooks:

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    class CustomMessageListBloc extends MessageListBloc {
      CustomMessageListBloc({required User user}) : super(user: user);

      @override
      void onItemAdded(BaseMessage item, List<BaseMessage> updatedList) {
        // Custom logic when a message is added
        super.onItemAdded(item, updatedList);
      }
    }
    ```
  </Tab>
</Tabs>

For `ListBase` override hooks (`onItemAdded`, `onItemRemoved`, `onItemUpdated`, `onListCleared`, `onListReplaced`), see [BLoC & Data — ListBase Hooks](/ui-kit/flutter/customization-bloc-data#listbase-hooks).

### Public BLoC Events

| Event | Description |
| - | - |
| `LoadMessages(conversationWith, conversationType)` | Load initial messages |
| `LoadOlderMessages()` | Load older messages (scroll up) |
| `LoadNewerMessages()` | Load newer messages (scroll down) |
| `RefreshMessages()` | Refresh from the latest |
| `SyncMessages()` | Silently sync missed messages |
| `JumpToMessage(messageId)` | Jump to a specific message |
| `AddReaction(message, reaction)` | Add a reaction |
| `RemoveReaction(message, reaction)` | Remove a reaction |
| `MarkMessageAsRead(message)` | Mark a message as read |
| `MarkMessageAsUnread(...)` | Mark a message as unread |
| `LoadFromUnread(conversationWith, conversationType)` | Load from first unread message |

### Public BLoC Methods

#### O(1) Lookup Methods

| Method | Returns | Description |
| - | - | - |
| `findMessageIndex(messageId)` | `int?` | Find message index by ID |
| `findMessageIndexByMuid(muid)` | `int?` | Find message index by muid (pending messages) |
| `findMessage(messageId)` | `BaseMessage?` | Get message by ID |
| `findMessageByMuid(muid)` | `BaseMessage?` | Get message by muid |

#### ValueNotifier Accessors (Isolated Rebuilds)

| Method | Returns | Description |
| - | - | - |
| `getReceiptNotifier(messageId)` | `ValueNotifier<MessageReceiptStatus>` | Per-message receipt status notifier |
| `getReceiptNotifierForMessage(message)` | `ValueNotifier<MessageReceiptStatus>` | Receipt notifier handling both ID and muid |
| `getTypingNotifier(conversationId)` | `ValueNotifier<List<TypingIndicator>>` | Per-conversation typing notifier |
| `getThreadReplyCountNotifier(parentMessageId)` | `ValueNotifier<int>` | Per-message thread reply count notifier |

#### MessageReceiptStatus Enum

| Value | Description |
| - | - |
| `sending` | Message is being sent (id = 0) |
| `sent` | Message has been sent to server |
| `delivered` | Message has been delivered to recipient |
| `read` | Message has been read by recipient |
| `error` | Message failed to send |

### Operations Stream

The BLoC exposes an `operationsStream` consumed by `CometChatAnimatedMessageList` for smooth animations:

| Operation | Description |
| - | - |
| `MessageOperation.insert(message, index)` | Insert a single message |
| `MessageOperation.insertAll(messages, index)` | Insert a batch of messages |
| `MessageOperation.update(oldMessage, newMessage, index)` | Replace a message in-place |
| `MessageOperation.remove(message, index)` | Remove a message |
| `MessageOperation.set(messages)` | Replace the entire list |

***

## Style

<Tabs>
  <Tab title="Dart">
    ```dart theme={null}
    CometChatMessageList(
      user: user,
      style: CometChatMessageListStyle(
        backgroundColor: Color(0xFFFEEDE1),
        outgoingMessageBubbleStyle: CometChatOutgoingMessageBubbleStyle(
          backgroundColor: Color(0xFFF76808),
        ),
        incomingMessageBubbleStyle: CometChatIncomingMessageBubbleStyle(
          backgroundColor: Colors.white,
        ),
      ),
    )
    ```
  </Tab>
</Tabs>

See [Component Styling](/ui-kit/flutter/component-styling) and [Message Bubble Styling](/ui-kit/flutter/message-bubble-styling) for the full reference.

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Message Header" icon="heading" href="/ui-kit/flutter/message-header">
    Display user/group info in the app bar
  </Card>

  <Card title="Message Composer" icon="pen-to-square" href="/ui-kit/flutter/message-composer">
    Rich input for sending messages
  </Card>

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

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


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