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

# Custom Text Formatter

> Extend CometChatTextFormatter to build custom inline text patterns with tracking characters and suggestion lists.

<Accordion title="AI Integration Quick Reference">
  | Field          | Value                                                                                                                                                                            |
  | -------------- | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
  | Package        | `com.cometchat:chat-uikit-android`                                                                                                                                               |
  | Key class      | `CometChatTextFormatter` (abstract base class for custom formatters)                                                                                                             |
  | Required setup | `CometChatUIKit.init()` then `CometChatUIKit.login("UID")`                                                                                                                       |
  | Purpose        | Extend to create custom inline text patterns with tracking characters, suggestion lists, and span formatting                                                                     |
  | Features       | Tracking character activation, suggestion list, span formatting per context (composer, bubbles, conversations), pre-send hooks                                                   |
  | Sample app     | [GitHub](https://github.com/cometchat/cometchat-uikit-android/tree/v5/sample-app-kotlin)                                                                                         |
  | Related        | [Mentions Formatter](/ui-kit/android/mentions-formatter-guide) \| [ShortCut Formatter](/ui-kit/android/shortcut-formatter-guide) \| [All Guides](/ui-kit/android/guide-overview) |
</Accordion>

`CometChatTextFormatter` is an abstract class for formatting text in the message composer and message bubbles. Extend it to build custom formatters — hashtags, shortcuts, or any pattern triggered by a tracking character.

| Capability            | Description                                                                                     |
| --------------------- | ----------------------------------------------------------------------------------------------- |
| Tracking character    | Activates the formatter when the user types a specific character (e.g., `#`, `!`)               |
| Suggestion list       | Populates a dropdown of `SuggestionItem` objects as the user types                              |
| Span formatting       | Applies `SpannableStringBuilder` spans per context: composer, left/right bubbles, conversations |
| Pre-send hook         | `handlePreMessageSend` lets you modify the message before it's sent                             |
| Component integration | Plugs into any component via `setTextFormatters()`                                              |

***

## Steps

### 1. Create a class extending CometChatTextFormatter

Pass your tracking character to the superclass constructor.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    class HashTagFormatter : CometChatTextFormatter('#') {
        private val suggestions: MutableList<SuggestionItem> = ArrayList()
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    public class HashTagFormatter extends CometChatTextFormatter {
        private List<SuggestionItem> suggestions = new ArrayList<>();

        public HashTagFormatter() {
            super('#');
        }
    }
    ```
  </Tab>
</Tabs>

### 2. Override the search method

Called when the user types after the tracking character. Match input against your data and update the suggestion list.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    override fun search(context: Context, queryString: String?) {
        suggestions.clear()
        val query = "#${queryString ?: ""}"
        // Match against your hashtag data source
        val matchingTags = getMatchingTags(query)
        for (tag in matchingTags) {
            val item = SuggestionItem("", tag, null, null, tag, null, null)
            item.isHideLeadingIcon = true
            suggestions.add(item)
        }
        setSuggestionItemList(suggestions)
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    @Override
    public void search(@NonNull Context context, @Nullable String queryString) {
        suggestions.clear();
        String query = "#" + (queryString != null ? queryString : "");
        // Match against your hashtag data source
        List<String> matchingTags = getMatchingTags(query);
        for (String tag : matchingTags) {
            SuggestionItem item = new SuggestionItem("", tag, null, null, tag, null, null);
            item.setHideLeadingIcon(true);
            suggestions.add(item);
        }
        setSuggestionItemList(suggestions);
    }
    ```
  </Tab>
</Tabs>

### 3. Override onScrollToBottom

Required by the base class. Implement pagination logic or leave empty.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin theme={null}
    override fun onScrollToBottom() {
        // Load more suggestions if needed
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java theme={null}
    @Override
    public void onScrollToBottom() {
        // Load more suggestions if needed
    }
    ```
  </Tab>
</Tabs>

### 4. Override span formatting methods (optional)

Customize how matched text renders in different contexts using `SpannableStringBuilder`.

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    override fun prepareLeftMessageBubbleSpan(
        context: Context, baseMessage: BaseMessage, spannable: SpannableStringBuilder
    ): SpannableStringBuilder? {
        // Apply custom spans for incoming message bubbles
        return applyHashTagSpans(spannable, Color.parseColor("#5dff05"))
    }

    override fun prepareRightMessageBubbleSpan(
        context: Context, baseMessage: BaseMessage, spannable: SpannableStringBuilder
    ): SpannableStringBuilder? {
        // Apply custom spans for outgoing message bubbles
        return applyHashTagSpans(spannable, Color.parseColor("#30b3ff"))
    }
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    @Override
    public SpannableStringBuilder prepareLeftMessageBubbleSpan(
        @NonNull Context context, @NonNull BaseMessage baseMessage, SpannableStringBuilder spannable) {
        return applyHashTagSpans(spannable, Color.parseColor("#5dff05"));
    }

    @Override
    public SpannableStringBuilder prepareRightMessageBubbleSpan(
        @NonNull Context context, @NonNull BaseMessage baseMessage, SpannableStringBuilder spannable) {
        return applyHashTagSpans(spannable, Color.parseColor("#30b3ff"));
    }
    ```
  </Tab>
</Tabs>

### 5. Integrate with a component

<Tabs>
  <Tab title="Kotlin">
    ```kotlin lines theme={null}
    val textFormatters = CometChatUIKit.getDataSource().getTextFormatters(this, messageComposer.additionParameter)
    textFormatters.add(HashTagFormatter())
    messageComposer.setTextFormatters(textFormatters)
    ```
  </Tab>

  <Tab title="Java">
    ```java lines theme={null}
    List<CometChatTextFormatter> textFormatters = CometChatUIKit.getDataSource().getTextFormatters(this, messageComposer.getAdditionParameter());
    textFormatters.add(new HashTagFormatter());
    messageComposer.setTextFormatters(textFormatters);
    ```
  </Tab>
</Tabs>

Pass the same list to `CometChatMessageList` and `CometChatConversations` via their `setTextFormatters()` methods to apply formatting across all contexts.

***

## Methods Reference

| Method                                                                        | Description                                                                                            |
| ----------------------------------------------------------------------------- | ------------------------------------------------------------------------------------------------------ |
| `search(Context, String)`                                                     | Abstract — called when user types after the tracking character. Update the suggestion list here.       |
| `onScrollToBottom()`                                                          | Abstract — called when the suggestion list scrolls to the bottom. Implement pagination or leave empty. |
| `onItemClick(Context, SuggestionItem, User, Group)`                           | Called when a suggestion item is selected. Override to customize insertion behavior.                   |
| `handlePreMessageSend(Context, BaseMessage)`                                  | Called before a message is sent. Override to modify the message (e.g., add metadata).                  |
| `prepareLeftMessageBubbleSpan(Context, BaseMessage, SpannableStringBuilder)`  | Override to format text in incoming message bubbles.                                                   |
| `prepareRightMessageBubbleSpan(Context, BaseMessage, SpannableStringBuilder)` | Override to format text in outgoing message bubbles.                                                   |
| `prepareComposerSpan(Context, BaseMessage, SpannableStringBuilder)`           | Override to format text in the message composer.                                                       |
| `prepareConversationSpan(Context, BaseMessage, SpannableStringBuilder)`       | Override to format text in the conversations list preview.                                             |
| `setSuggestionItemList(List<SuggestionItem>)`                                 | Updates the suggestion dropdown with new items.                                                        |
| `setDisableSuggestions(boolean)`                                              | Disables the suggestion dropdown entirely. (`protected` — accessible from subclasses only.)            |
| `setInfoText(String)`                                                         | Sets informational text displayed above the suggestion list.                                           |
| `setInfoVisibility(boolean)`                                                  | Toggles visibility of the info text.                                                                   |
| `setShowLoadingIndicator(boolean)`                                            | Shows/hides a loading spinner in the suggestion dropdown.                                              |
| `getTrackingCharacter()`                                                      | Returns the tracking character passed to the constructor.                                              |

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Mentions Formatter" icon="at" href="/ui-kit/android/mentions-formatter-guide">
    Built-in @mention formatting with styled tokens
  </Card>

  <Card title="ShortCut Formatter" icon="bolt" href="/ui-kit/android/shortcut-formatter-guide">
    Shortcut text expansion via the message-shortcuts extension
  </Card>

  <Card title="All Guides" icon="book" href="/ui-kit/android/guide-overview">
    Browse all feature and formatter guides
  </Card>

  <Card title="Sample App" icon="github" href="https://github.com/cometchat/cometchat-uikit-android/tree/v5/sample-app-kotlin">
    Full working sample application on GitHub
  </Card>
</CardGroup>
