This post is part 1 of what is currently a 3 part series of updates to my SharePoint Framework application customizer as the capability has evolved since entering developer preview in June. Please see the links to parts 2 and 3 below.
Back in 2015, I published a post on this blog detailing the steps for implementing a custom site header and footer using a SharePoint-hosted add-in. The add-in contained:
1. An add-in part that provides an interface to configure the text and colors associated with the custom header and footer, storing the necessary values in the property bag of the site.
Issues with current add-in solution
While the add-in solution from that blog post worked great in SharePoint Online in 2015 (and still works great for SharePoint Online classic pages and SharePoint 2013/2016 on-premises today), SharePoint Online has evolved somewhat over the past two years.
Enter SharePoint Framework
To extend the functionality of my SharePoint-hosted add-in to modern pages using the SharePoint Framework, I created a new SharePoint client-side solution containing an application customizer extension to handle the rendering of the header and footer on all modern pages, reading the same configuration values from the site property bag that are set by the add-in part from my original SharePoint-hosted add-in.
Modern pages contain useful placeholders
When creating the original add-in, I had to do some manipulation of the DOM to insert the <div> elements representing the custom header and footer in the appropriate places on the page using jQuery’s .insertBefore() and .insertAfter() methods. These kinds of customizations are fragile and could break if Microsoft changed the IDs or locations of existing page elements I was referencing such as suiteBarTop or s4-bodycontainer. I was hoping to get away from this in my modern page solution.
To that end, SharePoint Framework Extensions now give us access to page placeholders representing well-known locations on the page where we can more reliably inject our customizations. These include PageHeader and PageFooter. Awesome, right?
Unfortunately, in my initial experiments with page placeholders, I identified some shortcomings that would prevent me from building a complete modern page header/footer solution that leverages them. Most notably, modern site pages do not contain the PageFooter placeholder at all. Also, since my current solution renders the header at the very top of the page, I wasn’t a fan of the PageHeader placeholder location beneath the #suiteBarTop <div> instead of above it at the very top of the page.
SharePoint Framework page placeholders render the PageHeader below the suiteBarTop <div> and do not render a PageFooter on modern site pages, as shown above.
NOTE: This approach still relies on DOM manipulation and is a fragile and unsupported way to make user interface customizations to modern pages because of dependencies on page elements with specific IDs and CSS classes. In your solutions, please make every effort to leverage the supported page placeholders if possible.
With these limitations in mind and for the sake of a consistent look and feel across all pages (both classic and modern), I decided to stick with my jQuery-based approach of using .insertBefore() and .insertAfter() to inject my custom header and footer at the top and bottom of the page. While investigating the DOM on modern pages to determine where I would need to inject my header and footer, I realized that not all modern pages are created alike. Perhaps this is part of the reason why modern site pages do not contain a PageFooter placeholder…
The <div> element representing the page content on modern list and library view pages (and the modern Site Contents page) has an ID of spoAppComponent. This <div> does not exist on modern site pages. On modern site pages, the <div> element representing the page content has a class of SPPageChrome. (NOTE: modern list and library view pages also contain a <div> with a class of SPPageChrome, but this <div> does not represent the main content area on those pages.)
Page content areas on a modern list/library view page (left) and a modern site page (right) with the custom header and footer injected around them.
In my code, you will see that I test for the existence of #spoAppComponent on the page. If it exists, I know I’m on a modern list or library view page and I inject the custom header and footer around that <div>. Otherwise, I add the header and footer around the <div> with class SPPageChrome.
Building the Application Customizer
I followed the step-by-step instructions from the four-part Office Dev Center article series Build your first extension to generate, build, and deploy my application customizer. The following notes may be useful to you:
– If you have already installed a previous version of Microsoft’s Yeoman SharePoint Client-side Solution Generator, you will need to update it by running npm update -g @microsoft/generator-sharepoint. The current version of the generator (as of the publishing of this post) is now 1.1.1.
– If you haven’t updated your SharePoint Framework development environment in awhile, you may want to run npm update -g to ensure the rest of your global packages are up-to-date as well.
– Since I didn’t make use of any ClientSideComponentProperties, I removed that attribute from my ./sharepoint/assets/elements.xml file.
– If you download this code, you will need to update the CDN URL in the ./config/write-manifests.json file to match the location where you deploy the assets from the ./temp/deploy folder in your environment. More information about working with the Office 365 CDN may be found here.
– Remember that you must upload the .sppkg file from the ./sharepoint/solution folder to your tenant’s app catalog site, then add the associated app on your site. This will provision and activate the feature that deploys the application customizer to your site.
My code is posted to GitHub at the following location:
I encourage you to download it, try it out in your environment, and let me know if you run into any issues with it. Please keep the following things in mind:
– You must also install the SharePoint-hosted add-in located here in order to configure the header and footer property bag values and render them on classic pages.
This is a very exciting time to be doing modern SharePoint development. SharePoint Framework extensions reached GA in September 2017 and even more new capabilities and options for modern SharePoint customizations are still in the pipeline. Keep an eye on the SharePoint Framework wiki for more announcements and updates!