Skip to content

Salesforce LWC – Dynamic Social Icons Component for experience cloud using Navigation Menu

This is an enhanced version of Social Icon’s Lightning Web Component, as described in this Salesforce Developer post titled: Advanced Community Navigation Components

The idea is to have a navigation menu having social links with customizable icons that allow for the addition, removal, or updating of social media links and icons without the need to modify the underlying LWC code.

The enhancements include.

  1. Usage of the Salesforce ConnectApi to get navigation items instead of using obsolete chatter API.
  2. The navigation menu is not hard-coded and allows you to select any navigation menu while putting the component on the experience cloud site.
  3. The component is accessible by the guest user, the guest user profile needs the read permission on the Documents object.

To begin, create a navigation menu in the Salesforce Experience Cloud by Setup > Navigation > + Add Navigation Menu. As shown in the attached screenshot.

Download Social Media Icons from here and upload the icon image against each social media platform in the navigation menu item.

Now create an apex class that will be used as an LWC controller.

/**
* A basic controller for fetching NavigationLinkSet.
*/
global without sharing class NavigationMenuItemsController {
    
    @AuraEnabled(Cacheable=true)
    public static ConnectApi.NavigationMenuItemCollection getConnectNavigationItems(String menuName, String communityId) {
        
        List<NavigationLinkSet> navigationLinkSets = [
            SELECT Id
            FROM NavigationLinkSet
            WHERE DeveloperName = :menuName
            //WITH SECURITY_ENFORCED
            LIMIT 1
        ];
        NavigationLinkSet navigationLinkSet = (navigationLinkSets.size() == 1)
            ? navigationLinkSets.get(0)
            : null;

        ConnectApi.NavigationMenuItemCollection navigationItems = ConnectApi.NavigationMenu.getCommunityNavigationMenu(communityId, navigationLinkSet.Id, NULL, ConnectApi.PublishStatus.Draft, true, false, NULL);
        system.debug(navigationItems);
        
        return navigationItems;
    }
}

Apex class to fetch navigation menus to be used in LWC to allow users to select a navigation menu.

global class NavigationLinkSetPickList extends VisualEditor.DynamicPickList {
    
    global override VisualEditor.DataRow getDefaultValue() {
        VisualEditor.DataRow defaultValue = new VisualEditor.DataRow(
            'Default Navigation',
            'Default Navigation'
        );
        return defaultValue;
    }

    global override VisualEditor.DynamicPickListRows getValues() {
        String networkId = Network.getNetworkId();
        system.debug('networkId::'+networkId);
        
        VisualEditor.DynamicPickListRows picklistValues = new VisualEditor.DynamicPickListRows();
        List<NavigationLinkSet> navigationLinkSetList = [
            SELECT MasterLabel, DeveloperName, NetworkId
            FROM NavigationLinkSet 
        ];
        for (NavigationLinkSet navigationLinkSet : navigationLinkSetList) {
            VisualEditor.DataRow value = new VisualEditor.DataRow(
                navigationLinkSet.MasterLabel,
                navigationLinkSet.DeveloperName
            );
            picklistValues.addRow(value);
        }
        return picklistValues;
    }
}

Create a lightning web component with the name: SocialNavigation

<template>
    <div class="slds-grid slds-wrap slds-align--absolute-center">
      <div style={contentContainer}>
        <div class="slds-size--1-of-1">
          <div class="slds-grid slds-align--absolute-center">
            <template for:each={menuItems} for:item="item" for:index="i">
              <div key={item.label} class="slds-col slds-p-around--small">
                <template if:true={item.imageUrl}>
                  <img
                    data-label={item.label}
                    src={item.imageUrl}
                    class="nav-item-content"
                    onclick={navigateToItem}
                  />
                </template>
              </div>
            </template>
          </div>
        </div>
      </div>
    </div>
  </template>

LWC CSS: SocialNavigation.css

.nav-item-content {
    max-width: 100%;
    max-height: 100%;
  }

LWC Javascript file: SocialNavigation.js

import { LightningElement, api, track, wire } from "lwc";

// We can get our community Id for use in the callout
import communityId from "@salesforce/community/Id";

// Get our base path for navigating to non-named pages
import communityBasePath from "@salesforce/community/basePath";

// Our Apex method will allow us to retrieve the items
import getConnectNavigationItems from "@salesforce/apex/NavigationMenuItemsController.getConnectNavigationItems";

// Lightning Navigation Service will allow us to navigate to our target
import { NavigationMixin } from "lightning/navigation";

export default class SocialNavigation extends NavigationMixin(LightningElement) {
    @api menuName;
    @track menuItems = [];
    @api maxWidth = "400"; // Default to 400px
    communityId = communityId;
    communityBasePath = communityBasePath;
    error;
    baseUrl;

    connectedCallback() {
        let urlString = window.location.href;
        this.baseUrl = urlString.substring(0, urlString.indexOf("/s"));
    }

    @wire(getConnectNavigationItems, {
        menuName: "$menuName",
        communityId: "$communityId"
    })
    wiredNavigationItems({ error, data }) {
        if (data) {
            console.log('nav items::', JSON.stringify(data));
            this.menuItems = data.menuItems;
        } else if (error) {
            console.log('nav item error::', JSON.stringify(error));
            this.error = error;
        }
    }

    get contentContainer() {
        return "max-width:" + this.maxWidth + "px;";
    }

    navigateToItem(event) {
        // Get the menu item's label from the target
        let selectedLabel = event.currentTarget.dataset.label;

        // Loop through the menu items and get the row of the selected item
        let item = this.menuItems.filter(menuItem => menuItem.label === selectedLabel)[0];
        console.log('item::',JSON.stringify(item));
        // Distribute the action to the relevant mechanism for navigation
        if (item.actionType === "ExternalLink") {
            this.navigateToExternalPage(item);
        } else if (item.actionType === "InternalLink") {
            this.navigateToInternalPage(item);
        }
    }

    // Open the external link
    navigateToExternalPage(item) {
        const url = item.actionValue;
        if (item.target === "CurrentWindow") {
            this[NavigationMixin.Navigate]({
                type: "standard__webPage",
                attributes: {
                    url: url
                }
            });
        } else if (item.target === "NewWindow") {
            window.open(url, "_blank");
        }
    }

    // Open an internal link
    navigateToInternalPage(item) {
        const url = this.communityBasePath + item.actionValue;
        console.log(url);
        const url2 = this.baseUrl + "/s" + item.actionValue;
        console.log(url2);

        this[NavigationMixin.Navigate]({
            type: "standard__webPage",
            attributes: {
                url: url2
            }
        });
    }
}

LWC XML: SocialNavigation.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>
    <masterLabel>Social Links</masterLabel>
    <targets>
        <target>lightningCommunity__Page</target>
        <target>lightningCommunity__Default</target>
    </targets>
    <targetConfigs>
        <targetConfig targets="lightningCommunity__Default">
            <property
                name="menuName"
                type="String"
                datasource="apex://NavigationLinkSetPickList"
                label="Navigation Menu Name"
                description="The name of the Navigation Menu, which can be configured in Settings > Navigation"
            />
        </targetConfig>
    </targetConfigs>
</LightningComponentBundle>

Now put the LWC on the experience cloud site and the result will look like the below screenshot.

RESULT