spfxsharepoint-2019spfx-extension

How to Inject CSS or JavaScript to SharePoint Modern page using SPFX on Sharepoint Server 2019


We are using Sharepoint Modern communication site on Sharepoint Server 2019. I am tasked with customizing the out-of-the-box template for header and adding a footer. I was toying with using https://github.com/pnp/sp-dev-fx-extensions/tree/main/samples/react-application-injectcss but I am unable to get it to work. The SPPKG file throws the following error when I deploy it to Sharepoint Server 2019 apps.

There were errors when validating the App manifest.:Xml Validation Exception: 'The 'IsDomainIsolated' attribute is not declared.' on line '1', position '322'.

Please help. Thanks


Solution

  • You have to create new project because that sample is using spfx 1.8.0. For SharePoint 2019 you have to use spfx ~1.4.0.

    I have my own ApplicationCustomizer with custom css inside for branding ShP 2019.

    import { override } from '@microsoft/decorators';
    import { Log } from '@microsoft/sp-core-library';
    import { BaseApplicationCustomizer } from '@microsoft/sp-application-base';
    import * as $ from 'jquery';
    import styles from './css/styles.module.scss';
    require('./css/styles.module.scss');
    
    export default class BrandingApplicationCustomizer extends BaseApplicationCustomizer<{}> {
      @override
      public async onInit(): Promise<any> {
        try {
          await this.wait('.o365cs-nav-centerAlign');
          if (window.screen.availWidth < 639) {
            $('.o365cs-nav-centerAlign').css({"height":"50px", "cursor":"pointer", "background":"url(https://.../_layouts/15/Intranet.Design/Img/_intranet_logo.png) no-repeat left center"});
        $('.o365cs-nav-centerAlign').click(function() {
          window.location.href = 'https://intranet';
        });
      } else {
        $('.o365cs-nav-centerAlign').html(`
        <div class=` + styles.brandingMainDiv + `>
          <a href='https://intranet' style='line-height: 46px;'>
            <img src='https://intranet./_layouts/15/Intranet.Design/Img/_intranet_logo.png' style='margin: auto;vertical-align: middle;display: inline-block;'/>
          </a>
          <div style='margin-left:15px;border-left:1px solid white;'></div>
          <a href='` + this.context.pageContext.web.absoluteUrl + `'>
            <div style='font-family: Segoe UI Regular WestEuropean,Segoe UI,Tahoma,Arial,sans-serif;line-height: 40px;display: inline-block;font-size: 20px;-webkit-font-smoothing: antialiased;margin: 0px 0 0 25px;vertical-align: top;font-weight: bold;color:white;'>
            ` + this.context.pageContext.web.title + `</div></a></div>
         `);
         }
        } catch (error) {
    };
    return Promise.resolve();
      }
       private wait = (selector) => {
        return new Promise((resolve, reject) => {
      const waitForEl = (selector, count = 0) => {
        const el = $(selector);
        if (el.length > 0) {
          resolve(el);
        } else {
          setTimeout(() => {
            count++;
            if (count < 1000) {
              waitForEl(selector, count);
            } else {
              reject('Error: More than 1000 attempts to wait for element');
            }
          }, 100);
        }
      };
      waitForEl(selector);
        });
      }
    }
    

    Css looks like this (in scss you need to use global atribute):

    :global {
    .CanvasZone,
    .SPCanvas-canvas {
        max-width: none !important;
    }
    button[data-automation-id="pageCommandBarNewButton"] {
        display: none !important;
    }
    body, /* entire body*/
    .ms-Nav, /*left navigation pane background*/
    #spPageChromeAppDiv /* whole page again*/
    {
        background-color: #eeece1  !important;
    }
    .o365cs-base.o365cs-topnavBGColor-2, /* top bar*/
    .o365cs-base .o365cs-nav-rightMenus /* top bar menu right*/
    {
        background-color: #17375e !important;
    }
    #O365_MainLink_Help,
    #O365_NavHeader button#O365_MainLink_NavMenu,
    #O365_NavHeader button#O365_MainLink_NavMenu_Responsive,
    .o365button.o365cs-nav-appTitle.o365cs-topnavText,
    .o365cs-nav-topItem.o365cs-rsp-m-hide.o365cs-rsp-tn-hideIfAffordanceOn,
    .o365button .o365cs-nav-brandingText,
    .o365cs-nav-brandingText /* Top bar Sharepoint text*/
    {
        display: none !important;
    }