Customize the Messaging Conversation Window Header Using LWC

You can customize the messaging conversation window header using a custom conversation header Lightning Web Component (LWC).

These steps show you how to create a messaging conversation window header using a custom LWC. The sample code creates a header, as shown in the screenshot. The code includes:

We left these features out of this example to keep the sample code short, but you can add them later to your LWC with your own custom code.

  • Header announcements
  • Accessibility
  • Right-to-left language handling
  • A minimize button in the mobile version’s header—In the browser, you can minimize the window with the default floating action button, but the mobile version doesn’t have that.

Custom messaging conversation window header

  1. Create an LWC bundle. See Salesforce Trailhead: Build Lightning Web Components.

    Let's call our example bundle customHeader.

  2. In the customHeader.js-meta.xml configuration file of your LWC, specify the lightningSnapin__MessagingHeader target.

    You add this target to the configuration file so you can see the LWC in your Enhanced Web Chat experience. In other words, adding this target makes the LWC available for selection in Custom UI Components in Embedded Service Deployments in Setup. See Customize your UI with Lightning Web Components.

    customHeader.js-meta.xml
    <?xml version="1.0" encoding="UTF-8"?>
    <LightningComponentBundle xmlns="http://soap.sforce.com/2006/04/metadata">
     <apiVersion>60.0</apiVersion>
     <isExposed>true</isExposed>
     <targets>
         <target>lightningSnapin__MessagingHeader</target>
     </targets>
    </LightningComponentBundle>
  3. In the customHeader.js file, use these methods to customize the header.

    1. To connect your custom component to Embedded Service, import the dispatchMessagingEvent, assignMessagingEventHandler, and MESSAGING_EVENT methods from the public event store lightningsnapin/eventStore.

      import { dispatchMessagingEvent, assignMessagingEventHandler, MESSAGING_EVENT } from "lightningsnapin/eventStore";
    2. To dispatch a Messaging event, use dispatchMessagingEvent. See Messaging Conversation Window Header Events dfor all available Messaging header events.

      /**
      * Dispatch all public event handlers with data for a given event.
      * @param {String} eventName - Name of event to dispatch. Can't be null.
      * @param {Object} eventData - Data to pass to each event handler.
      *                             Can't be null. Use empty object {} if you're passing no data.
      */
      dispatchMessagingEvent(eventName, eventData);
    3. To listen to a Messaging event, use assignMessagingEventHandler.

      /**
      * Assign a public event handler for an event.
      * @param {String} eventName - Name of the event to assign a handler.
      * @param {Function} eventHandler - Function to assign to the event.
      */
      assignMessagingEventHandler(eventName, eventHandler);
    customHeader.js
    import { LightningElement, api } from "lwc";
    import { dispatchMessagingEvent, assignMessagingEventHandler, MESSAGING_EVENT } from "lightningsnapin/eventStore";
    
    const SLDS_MENU_SELECTOR = "slds-dropdown-trigger slds-dropdown-trigger_click";
    
    export default class ChatHeader extends LightningElement {
      /**
      * Deployment configuration data.
      * @type {Object}
      */
      @api configuration = {};
    
      /**
      * The status of the conversation. Valid values:
      * - NOT_STARTED
      * - OPEN
      * - CLOSED
      * @type {ConversationStatus}
      */
      @api conversationStatus;
    
      /**
      * Class name for header menu.
      * @type {String}
      */
      menuClass = SLDS_MENU_SELECTOR;
    
      /**
      * Array to store bot options menu.
      * @type {Array}
      */
      chatbotOptionsMenu = [];
    
      /**
      * Whether the use is authenticated.
      * AuthMode can have the following values:
      * - Auth: user is in verified, which corresponds to the authenticated user mode.
      * - UnAuth: user is in unverified,  which corresponds to the guest user mode.
      */
      get isAuthenticatedContext() {
          return this.configuration.embeddedServiceMessagingChannel.authMode === "Auth";
      }
    
      /**
      * Whether to show the back button.
      * @type {Boolean}
      */
      showBackButton = false;
    
      /**
      * Whether to show the header menu button.
      * @returns {Boolean}
      */
      get showMenuButton() {
          return this.conversationStatus === "OPEN";
      }
    
      /**
      * Whether to show the header menu.
      * @type {Boolean}
      */
      _showMenu = false;
      get showMenu() {
          return this._showMenu;
      }
      set showMenu(shouldShow) {
          this.menuClass = SLDS_MENU_SELECTOR + (shouldShow ? " slds-is-open" : "");
          this._showMenu = shouldShow;
      }
    
      /**
      * Whether to show the close button.
      * @returns {Boolean}
      */
      get showCloseButton() {
          return this.conversationStatus !== "OPEN";
      }
    
      /**
      * Handle back button click.
      */
      onBackButtonClick() {
          dispatchMessagingEvent(MESSAGING_EVENT.BACK_BUTTON_CLICK, {});
      }
    
      /**
      * Handle menu button click.
      */
      onMenuButtonClick() {
          this.showMenu = !this.showMenu;
      }
    
      /**
      * Handle minimize button click.
      */
      onMinimizeButtonClick() {
          dispatchMessagingEvent(MESSAGING_EVENT.MINIMIZE_BUTTON_CLICK, {});
      }
    
      /**
      * Handle close button click.
      */
      onCloseButtonClick() {
          dispatchMessagingEvent(MESSAGING_EVENT.CLOSE_CONTAINER, {});
      }
    
      /**
      * Handle end conversation button click.
      */
      onMenuOptionClick(event) {
          event.preventDefault();
    
          dispatchMessagingEvent(MESSAGING_EVENT.MENU_ITEM_SELECTED, {
              selectedOption: this.chatbotOptionsMenu.find(option => option.optionIdentifier === event.target.getAttribute("value"))
          });
    
          this.showMenu = false;
      }
    
    /**
    * Handle end chat button click.
    *
    * Ending a messaging session is only supported for verified users.
    * Ending a conversation is only supported for unverified users.
    */
    onEndChatClick() {
        if (this.isAuthenticatedContext) {
            this.configuration.util.endSession();
        } else {
            dispatchMessagingEvent(MESSAGING_EVENT.CLOSE_CONVERSATION, {});
        }
    
        this.showMenu = false;
    }
    
      connectedCallback() {
          assignMessagingEventHandler(MESSAGING_EVENT.PARTICIPANT_JOINED, (data) => {
              console.log(`Participant joined`);
    
              if (data.options && Array.isArray(data.options)) {
                  data.options.forEach((participantOption) => {
                      this.chatbotOptionsMenu.push(participantOption);
                  });
              }
          });
    
          assignMessagingEventHandler(MESSAGING_EVENT.PARTICIPANT_LEFT, (data) => {
              console.log(`Participant left`);
    
              this.chatbotOptionsMenu = [];
          });
    
          assignMessagingEventHandler(MESSAGING_EVENT.UPDATE_HEADER_TEXT, (data) => {
              console.log(`Update header text: ${data.text}`);
          });
    
          assignMessagingEventHandler(MESSAGING_EVENT.TOGGLE_BACK_BUTTON, (data) => {
              console.log(`Toggle back button visibility.`);
    
              this.showBackButton = data.showBackButton;
          });
      }
    }
  4. In the customHeader.html file, add all the header components and buttons to render in the UI.

    customHeader.html
    <template>
        <!-- Back button -->
        <template if:true={showBackButton}>
            <button class="headerButton backButton" onclick={onBackButtonClick}>
                <lightning-icon icon-name="utility:back" variant="inverse" size="x-small"></lightning-icon>
            </button>
        </template>
    
        <!-- Header menu -->
        <section class={menuClass}>
            <template if:true={showMenuButton}>
                <!-- Menu button -->
                <button class="headerButton menuButton" onclick={onMenuButtonClick}>
                    <lightning-icon icon-name="utility:threedots_vertical" variant="inverse" size="x-small"></lightning-icon>
                </button>
            </template>
    
            <!-- Menu options-->
            <section class="optionsMenu slds-dropdown slds-dropdown_left slds-nubbin_top-left">
                <ul class="slds-dropdown__list">
                    <!-- Bot menu options -->
                    <template for:each={chatbotOptionsMenu} for:item="option">
                        <li class="slds-dropdown__item" key={option.optionIdentifier}>
                            <button class="chatbotMenuOption"
                                    value={option.optionIdentifier}
                                    onclick={onMenuOptionClick}>
                                <span value={option.optionIdentifier}>{option.title}</span>
                            </button>
                        </li>
                    </template>
    
                <!-- End chat option -->
                <li class="slds-dropdown__item">
                    <button class="chatbotMenuOption"
                            onclick={onEndChatClick}>
                        <span class="slds-text-color_error">End Chat</span>
                    </button>
                </li>
                </ul>
            </section>
        </section>
    
        <!-- Header logo -->
        <!-- Replace this with your logo file. -->
        <img src="/path/to/logo.png" alt="My Logo"/>
    
        <!-- Header text -->
        <h2>Custom Header</h2>
    
        <!-- Minimize button -->
        <button class="headerButton minimizeButton" onclick={onMinimizeButtonClick}>
            <lightning-icon icon-name="utility:chevrondown" variant="inverse" size="x-small"></lightning-icon>
        </button>
    
        <!-- Close button -->
        <template if:true={showCloseButton}>
            <button class="headerButton closeButton" onclick={onCloseButtonClick}>
                <lightning-icon icon-name="utility:close" variant="inverse" size="x-small"></lightning-icon>
            </button>
        </template>
    </template>
  5. In the customHeader.css file, customize the UI style of the header components and buttons.

    customHeader.css
    :host {
        width: 100%;
        max-width: 100%;
        min-height: 50px;
        display: flex;
        align-items: center;
        box-sizing: border-box;
        position: relative;
        padding: 0 14px;
        height: 50px;
        max-height: 50px;
        background-color: black;
    }
    
    img {
        margin-right: 4px;
        max-height: 40px;
        max-width: 40px;
    }
    
    h2 {
        margin: 0;
        text-align: initial;
        align-self: center;
        flex-grow: 1;
        overflow: hidden;
        text-overflow: ellipsis;
        white-space: nowrap;
        font-weight: lighter;
        font-size: inherit;
        color: white;
    }
    
    .headerButton {
        background: none;
        border: none;
        display: inline-flex;
        height: 32px;
        min-height: 32px;
        width: 32px;
        min-width: 32px;
        align-items: center;
        justify-content: center;
    }
    
    .headerButton:hover:before {
        content: " ";
        position: absolute;
        top: 9px;
        width: 32px;
        height: 32px;
        background-color: #fff;
        opacity: .2;
        border-radius: 4px;
        box-sizing: border-box;
        pointer-events: none;
    }
    
    .headerButton.menuButton:hover:before {
        top: 0;
    }
    
    .headerButton.closeButton:hover:before {
        right: 14px;
    }
    
    lightning-icon {
        fill: white;
    }
    
    .optionsMenu {
        width: 100vw;
        left: -0.9rem;
    }
    
    .optionsMenu > .slds-dropdown__list {
        max-height: 20rem;
        overflow-y: auto;
    }
    
    .slds-nubbin_top-left:before,
    .slds-nubbin_top-left:after {
        left: 2rem;
        top: -0.5rem;
    }
    
    .slds-dropdown {
        max-width: 30rem;
    }
    
    .slds-dropdown__item > button {
        position: relative;
        z-index: 100;
        padding: 0.75rem 1rem;
        background-color: #ffffff;
        border: 0;
        display: flex;
        width: 100%;
    }
    
    .slds-dropdown__item > button:focus,
    .slds-dropdown__item > button:hover {
        outline: 0;
        text-decoration: none;
        background-color: #e5e5e5;
    }
    
    .slds-dropdown__list > .slds-dropdown__item:not(:first-child) {
        border-top: #e2e2e2 1px solid;
    }
    
    .slds-dropdown__item .slds-truncate:not(.closeConversation) {
        color: #005290;
    }
  6. Deploy the LWC to your org. See Salesforce Developer Guide: Introducing Lightning Web Components.

  7. Add the LWC to your Embedded Service Deployment. See Salesforce Help: Customize Your UI with Lightning Web Components. To get custom LWC configuration details, see Salesforce Developer Guide: Get Custom Lightning Web Components Configuration Details