In this guide, we will demonstrate how to add a custom message with a custom-built message bubble to the Message List component.
We recommend that you read the Key Concepts , follow the guidelines, and also take the time to familiarise yourself with the library’s components.
In the example below, we are going to simulate a “nudge” behaviour which sends out a custom message when the user clicks on the auxiliary button placed in the Message Composer component.

Custom Auxiliary Button

The first step is to create a new auxiliary button. We’ll be making use of CometChatIcon web component to create the auxiliary icon.
<cometchat-icon
  URL="assets/nudge-icon.png"
  [iconStyle]="iconStyle"
  (click)="sendMessage(item)"
></cometchat-icon>

Click Handler

We’ll send a custom message i.e. a Nudge when user clicks on the button.
sendMessage(item:CometChat.User | CometChat.Group){
  if(item instanceof CometChat.User){
    this.user = item
  } else {
    this.group = item
  }

  let { receiverId, receiverType } = this.getReceiverDetails();
  const customData = {nudge_url: "assets/rocket.gif"};
 	const customType = "nudge";
 	const customMessage: CometChat.CustomMessage = new CometChat.CustomMessage(receiverId, receiverType, customType, customData);
 	customMessage.setMetadata({ incrementUnreadCount: true });
 	(customMessage as any).setSentAt(CometChatUIKitUtility.getUnixTimestamp());
 	customMessage.setMuid(CometChatUIKitUtility.ID());
	CometChatUIKit.sendCustomMessage(customMessage)
}

getReceiverDetails() {
	let receiverId!: string;
	let receiverType!: string;
  if (this.user && this.user.getUid()) {
  	receiverId = this.user.getUid();
  	receiverType = CometChatUIKitConstants.MessageReceiverType.user;
  } else if (this.group && this.group.getGuid()) {
  	receiverId = this.group.getGuid();
  	receiverType = CometChatUIKitConstants.MessageReceiverType.group;
  }
	return { receiverId: receiverId, receiverType: receiverType };
}
The auxiliary button is then passed to the ConversationsWithMessages component as a prop using the MessagesConfiguration.
@ViewChild('auxButtonRef') auxButtonRef!:TemplateRef<any>;

messagesConfiguration:MessagesConfiguration = new MessagesConfiguration({});

ngAfterViewInit(){
	this.messagesConfiguration.messageComposerConfiguration.auxilaryButtonView = this.auxButtonRef;
}
We’ll create a new message template for the custom message and add to the list of pre-defined list of message templates. The pre-defined message templates are fetched using the CometChatUIKit class.
ngAfterViewInit() {

    let templates = CometChatUIKit.getDataSource().getAllMessageTemplates(this.themeService.theme);

    const messageTemplate = new CometChatMessageTemplate({
  options: this.getMessageOptions,
  contentView: () => this.imageBubbleRef,
  type: "nudge",
  category: "custom"
  });

    templates.push(messageTemplate);
}

getMessageOptions(loggedInUser: CometChat.User, message: CometChat.BaseMessage, theme: CometChatTheme, group?: CometChat.Group | undefined) {
	return CometChatUIKit.getDataSource().getCommonOptions(loggedInUser,message,theme,group)}
}
Now, we’ll add the custom message type to message request builder so that these custom messages can be pulled while fetching the historical messages.
let defaultTypes: string[] =
  CometChatUIKit.getDataSource().getAllMessageTypes();
let defaultCategory: string[] =
  CometChatUIKit.getDataSource().getAllMessageCategories();

if (!defaultCategory.includes("custom")) {
  defaultCategory.push("custom");
}

if (!defaultTypes.includes("nudge")) {
  defaultTypes.push("nudge");
}
The message request builder is then applied to the ConversationsWithMessages component using MessagesConfiguration.
this.messagesConfiguration.messageListConfiguration.templates = templates;
this.messagesConfiguration.messageListConfiguration.messagesRequestBuilder =
  new CometChat.MessagesRequestBuilder()
    .setLimit(30)
    .setTypes(defaultTypes)
    .setCategories(defaultCategory)
    .hideReplies(true);

Implementation

With the completion of each individual piece, we can now integrate all the code snippets to form the final code example.

Code

import { Component, ElementRef, HostListener, OnInit, TemplateRef, ViewChild } from '@angular/core';
import { CometChat } from '@cometchat/chat-sdk-javascript';
import '@cometchat/uikit-elements';
import { CometChatMessageComposerAction, CometChatMessageEvents, CometChatMessageOption, CometChatMessageTemplate, CometChatTheme, CometChatUIKitConstants, fontHelper } from '@cometchat/uikit-resources';
import { MessagesConfiguration,ComposerId, CometChatUIKitHelper, CometChatUIKitUtility, MessageStatus } from '@cometchat/uikit-shared';
import { CometChatUIKit, CometChatThemeService } from '@cometchat/chat-uikit-angular';

@Component({
  selector: 'app-auxiliary-button',
  templateUrl: './auxiliary-button.component.html',
  styleUrls: ['./auxiliary-button.component.scss']
})

export class AuxiliaryButtonComponent implements OnInit {

  //template ref for image bubble
  @ViewChild('auxButtonRef') auxButtonRef!:TemplateRef<any>;
  @ViewChild('imageBubbleRef') imageBubbleRef!:TemplateRef<any>;

  //properties
  iconStyle = { iconTint: this.themeService.theme.palette.getAccent600(), width: "24px", height: "24px"};
  messagesConfiguration:MessagesConfiguration = new MessagesConfiguration({});
  loggedInUser:CometChat.User | null = null;
  public  user!:CometChat.User;
  public  group!:CometChat.Group;

  //accessing global theme object.
  constructor(private themeService:CometChatThemeService){}

  ngAfterViewInit(){
    //default templates
    let templates = CometChatUIKit.getDataSource().getAllMessageTemplates(this.themeService.theme)

    const messageTemplate = new CometChatMessageTemplate({
      options: this.getMessageOptions,
      contentView: () => this.imageBubbleRef,
      type: "nudge",
      category: "custom"
    });

    //adding new template
    templates.push(messageTemplate)

    let defaultTypes:string[] = CometChatUIKit.getDataSource().getAllMessageTypes()
    let defaultCategory:string[] = CometChatUIKit.getDataSource().getAllMessageCategories()
    if(!defaultCategory.includes("custom")){
      defaultCategory.push("custom")
    }
    if(!defaultTypes.includes("nudge")){
      defaultTypes.push("nudge")
    }

    //creating new configuration
    this.messagesConfiguration.messageListConfiguration.templates = templates
    this.messagesConfiguration.messageListConfiguration.messagesRequestBuilder = new CometChat.MessagesRequestBuilder()
    .setLimit(30)
    .setTypes(defaultTypes)
    .setCategories(defaultCategory)
    .hideReplies(true);
    this.messagesConfiguration.messageComposerConfiguration.auxilaryButtonView = this.auxButtonRef;
    this.messagesConfiguration =  {...this.messagesConfiguration};
}

  sendMessage(item:CometChat.User | CometChat.Group){
    if(item instanceof CometChat.User){
      this.user = item
    } else {
      this.group = item
    }

    let { receiverId, receiverType } = this.getReceiverDetails();
    const customData = {nudge_url: "assets/rocket.gif"};
    const customType = "nudge";
    const customMessage: CometChat.CustomMessage = new CometChat.CustomMessage(receiverId, receiverType, customType, customData);
    customMessage.setMetadata({ incrementUnreadCount: true });
    (customMessage as any).setSentAt(CometChatUIKitUtility.getUnixTimestamp());
    customMessage.setMuid(CometChatUIKitUtility.ID());
    CometChatUIKit.sendCustomMessage(customMessage)
  }

  getReceiverDetails() {
    let receiverId!: string;
    let receiverType!: string;
    if (this.user && this.user.getUid()) {
      receiverId = this.user.getUid();
      receiverType = CometChatUIKitConstants.MessageReceiverType.user;
    } else if (this.group && this.group.getGuid()) {
      receiverId = this.group.getGuid();
      receiverType = CometChatUIKitConstants.MessageReceiverType.group;
    }
    return { receiverId: receiverId, receiverType: receiverType };
  }

   getMessageOptions(loggedInUser: CometChat.User, message: CometChat.BaseMessage, theme: CometChatTheme, group?: CometChat.Group | undefined) {
    return CometChatUIKit.getDataSource().getCommonOptions(loggedInUser,message,theme,group)}
  }

}