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

# ShortCut Formatter

> Implement !shortcut style text expansions with extension APIs or dialogs in CometChat Angular UI Kit.

<Accordion title="AI Integration Quick Reference">
  | Field           | Value                                                                                                                        |
  | --------------- | ---------------------------------------------------------------------------------------------------------------------------- |
  | Package         | `@cometchat/chat-uikit-angular`                                                                                              |
  | Key class       | `ShortcutFormatter` (extends `CometChatTextFormatter`)                                                                       |
  | Required setup  | `CometChatUIKit.init(uiKitSettings)` then `CometChatUIKit.login("UID")`                                                      |
  | Track character | `!` — triggers shortcut expansion in the message composer                                                                    |
  | Related         | [Custom Text Formatter](/ui-kit/angular/v5/guides/custom-text-formatter) \| [All Guides](/ui-kit/angular/v5/guides/overview) |
</Accordion>

`ShortCutFormatter` extends [CometChatTextFormatter](/ui-kit/angular/v5/guides/custom-text-formatter) to expand shortcodes (like `!hb`) into full text via the Message Shortcuts extension. When a user types a shortcut, a dialog appears with the expansion — clicking it inserts the text.

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-v6-beta2-flutter-uikit/l0BQw00NEQYzYvIU/images/af50b10c-shortcutformatter_overview_web_screens-4e5d3b6b65e42d8ce15bbb0f83605bfe.png?fit=max&auto=format&n=l0BQw00NEQYzYvIU&q=85&s=dd103e6176e4f37d8de8ebd51a4529bb" width="1282" height="802" data-path="images/af50b10c-shortcutformatter_overview_web_screens-4e5d3b6b65e42d8ce15bbb0f83605bfe.png" />
</Frame>

***

## Steps

### 1. Import the base class

```typescript theme={null}
import { CometChatTextFormatter } from "@cometchat/chat-uikit-angular";
```

### 2. Extend it

```typescript theme={null}
class ShortCutFormatter extends CometChatTextFormatter {
  // ...
}
```

### 3. Set the track character

```typescript theme={null}
this.setTrackingCharacter("!");
```

### 4. Handle key events

Detect shortcuts on `keyUp` and trigger expansion logic.

```typescript theme={null}
onKeyUp(event: KeyboardEvent) {
  // Check text before caret for shortcut match
}
```

### 5. Add dialog and formatting methods

```typescript theme={null}
openDialog(buttonText: string, shortcut: string) { /* ... */ }
closeDialog() { /* ... */ }
handleButtonClick(buttonText: string) { /* ... */ }
getFormattedText(text: string): string { return text; }
```

***

## Example

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-v6-beta2-flutter-uikit/l_OnVHhTFtMCxAJj/images/dd3e5fe4-shortcutformatter-1ea213ac1d135f72a85bb4dc4dabc50f.png?fit=max&auto=format&n=l_OnVHhTFtMCxAJj&q=85&s=49532eb5639e14ed854e1ad2419fb4b0" width="1282" height="802" data-path="images/dd3e5fe4-shortcutformatter-1ea213ac1d135f72a85bb4dc4dabc50f.png" />
</Frame>

<Frame>
  <img src="https://mintcdn.com/cometchat-22654f5b-docs-v6-beta2-flutter-uikit/F8Gwgh225UVQ2ohc/images/e5a9a16a-shortcutformatter_click_web_screens-b977681014e345970616f9d595132dfb.png?fit=max&auto=format&n=F8Gwgh225UVQ2ohc&q=85&s=668892f6348c160596bcba944c363dad" width="1282" height="802" data-path="images/e5a9a16a-shortcutformatter_click_web_screens-b977681014e345970616f9d595132dfb.png" />
</Frame>

<Tabs>
  <Tab title="ShortCutFormatter.ts">
    Fetches shortcuts from the Message Shortcuts extension on init. On `keyUp`, checks if the text before the caret matches a shortcut and opens a dialog with the expansion.

    ```typescript expandable theme={null}
    import { CometChatTextFormatter, CometChatUIEvents, PanelAlignment } from "@cometchat/chat-uikit-angular";
    import { CometChat } from "@cometchat/chat-sdk-javascript";

    export class ShortcutFormatter extends CometChatTextFormatter {
      private shortcuts: { [key: string]: string } = {};
      private dialogIsOpen = false;
      private currentShortcut: string | null = null;

      constructor() {
        super();
        this.setTrackingCharacter("!");
        CometChat.callExtension("message-shortcuts", "GET", "v1/fetch", undefined)
          .then((data: any) => {
            if (data?.shortcuts) {
              this.shortcuts = data.shortcuts;
            }
          })
          .catch((error) => console.error("Error fetching shortcuts", error));
      }

      onKeyUp(event: KeyboardEvent) {
        const caretPosition =
          this.currentCaretPosition instanceof Selection
            ? this.currentCaretPosition.anchorOffset
            : 0;
        const textBeforeCaret = this.getTextBeforeCaret(caretPosition);

        const match = textBeforeCaret.match(/!([a-zA-Z]+)$/);
        if (match) {
          const shortcut = match[0];
          const replacement = this.shortcuts[shortcut];
          if (replacement) {
            if (this.dialogIsOpen && this.currentShortcut !== shortcut) {
              this.closeDialog();
            }
            this.openDialog(replacement, shortcut);
          }
        } else if (!textBeforeCaret) {
          this.closeDialog();
        }
      }

      openDialog(buttonText: string, shortcut: string) {
        CometChatUIEvents.ccShowPanel.next({
          child: this.createDialogElement(buttonText),
          position: PanelAlignment.messageListFooter,
        });
        this.dialogIsOpen = true;
        this.currentShortcut = shortcut;
      }

      closeDialog() {
        CometChatUIEvents.ccHidePanel.next(PanelAlignment.messageListFooter);
        this.dialogIsOpen = false;
        this.currentShortcut = null;
      }

      private createDialogElement(buttonText: string): HTMLElement {
        const container = document.createElement("div");
        container.style.width = "100%";
        container.style.padding = "8px";

        const button = document.createElement("button");
        button.textContent = buttonText;
        button.style.cssText =
          "width: 100%; padding: 8px 16px; cursor: pointer; background: #f2e6ff; border: 2px solid #9b42f5; border-radius: 12px; text-align: left; font: 600 15px sans-serif;";
        button.addEventListener("click", () => this.handleButtonClick(buttonText));

        container.appendChild(button);
        return container;
      }

      handleButtonClick(buttonText: string) {
        if (this.currentCaretPosition && this.currentRange) {
          const shortcut = Object.keys(this.shortcuts).find(
            (key) => this.shortcuts[key] === buttonText
          );
          if (shortcut) {
            const replacement = this.shortcuts[shortcut];
            this.addAtCaretPosition(
              replacement,
              this.currentCaretPosition,
              this.currentRange
            );
          }
        }
        if (this.dialogIsOpen) {
          this.closeDialog();
        }
      }

      getFormattedText(text: string): string {
        return text;
      }

      private getTextBeforeCaret(caretPosition: number): string {
        if (
          this.currentRange?.startContainer &&
          typeof this.currentRange.startContainer.textContent === "string"
        ) {
          const textContent = this.currentRange.startContainer.textContent;
          if (textContent.length >= caretPosition) {
            return textContent.substring(0, caretPosition);
          }
        }
        return "";
      }
    }
    ```
  </Tab>

  <Tab title="Component Usage">
    Pass the formatter via the `textFormatters` input on the composer.

    ```typescript expandable theme={null}
    import { Component } from "@angular/core";
    import { CometChatMessageComposerComponent } from "@cometchat/chat-uikit-angular";
    import { ShortcutFormatter } from "./ShortCutFormatter";

    @Component({
      selector: "app-shortcut-demo",
      standalone: true,
      imports: [CometChatMessageComposerComponent],
      template: `
        <cometchat-message-composer
          [textFormatters]="textFormatters">
        </cometchat-message-composer>
      `,
    })
    export class ShortcutDemoComponent {
      textFormatters = [new ShortcutFormatter()];
    }
    ```
  </Tab>
</Tabs>

<Note>
  The Message Shortcuts extension must be enabled in your CometChat Dashboard for this formatter to work. Configure your shortcuts in the Dashboard under Extensions → Message Shortcuts.
</Note>

***

## Next Steps

<CardGroup cols={2}>
  <Card title="Custom Text Formatter" href="/ui-kit/angular/v5/guides/custom-text-formatter">
    Build custom inline text patterns.
  </Card>

  <Card title="Message Composer" href="/ui-kit/angular/v5/components/cometchat-message-composer">
    Customize the message input component.
  </Card>

  <Card title="All Guides" href="/ui-kit/angular/v5/guides/overview">
    Browse all feature and formatter guides.
  </Card>

  <Card title="Mentions Formatter" href="/ui-kit/angular/v5/guides/mentions-formatter">
    Add @mentions with styled tokens.
  </Card>
</CardGroup>
