Custom site header and footer using a SharePoint-hosted add-in
In this post, I will show you how to create a custom site header and footer for SharePoint Online/Office 365 that will render on all pages using a SharePoint-hosted add-in. This could be used to post critical alerts or to specify the level of business impact of the content stored within a particular site (e.g., high, medium, or low).
This add-in will accomplish the following, all without a single line of server-side code:
- Upon installation, deploy 3 JavaScript files to the Style Library of the host web
- Register 3 user custom actions in the host web to ensure these JavaScript files are loaded on every page
- Via an add-in part, provide a mechanism for users to enable/disable and set properties of the custom header and footer (e.g., message text, background/text color)
- Store and retrieve configuration parameters for the site header and footer in the host web’s property bag
Rendering a custom header and footer
We might be tempted to edit the master page directly to add a header and a footer, but this is not considered a best practice (especially in SharePoint Online, where master page changes can be rolled out quite frequently). Instead, our add-in will make use of JavaScript techniques to insert
- In SharePoint Online/Office 365, our header (with ID customHeader) will be inserted above thewith ID suiteBarTop (for SharePoint 2013 on-premises, you’ll need to update the script to reference ID suiteBar instead).
- Our footer
(with ID customFooter) will be inserted below thewith ID s4-bodyContainer.- NOTE: The
IDs in SharePoint Online are never set in stone and could change at any time. If they do, you will need to update HeaderFooter.js to reference the newIDs.jQuery makes it easy to create our custom header and footer
elements and insert them in the appropriate location within the DOM with its .insertBefore() and .insertAfter() functions following this approach:$("
HEADER TEXT").insertBefore("#suiteBarTop"); $(" ").insertAfter("#s4-bodyContainer");Making the footer “sticky”
Huge shout-out to Randy Drisgill for his SharePoint 2013 Sticky Footer implementation. The “sticky” footer anchors the footer
to the bottom of the page (or the bottom of the browser window if the available screen real estate exceeds the amount of content on a given page). I only needed to make one change to Randy’s StickyFooter.js implementation, and that was to account for the height offset imposed by the addition of our customHeader:var difference = windowheight - (bodyheight + ribbonheight + footerheight + $("#customHeader").outerHeight());
Provisioning files to the host web via JavaScript
For anyone following the OfficeDev PnP, the concept of remote provisioning to allow add-ins to deploy files to the host web should be a familiar one. However, the PnP examples make use of the .NET Managed CSOM to do this, which is a perfectly valid technique but would require us to develop a provider-hosted add-in (allowing that code to run in Azure or some other web server). Since I wanted to create a SharePoint-hosted add-in, I had to find a way to accomplish this using only JavaScript. Thankfully, I found Chris O’Brien’s post with code showing how to provision files to the host web using JavaScript. You will see that my code is based heavily on the example he provides and provisions the following files from the add-in web to the host web:
- jQuery-1.9.1.min.js – jQuery
- HeaderFooter.js – our logic to read the header/footer configuration data from the host web property bag and render the header and footerelements
- StickyFooter.js – Randy Drisgill’s Sticky Footer implementation for SharePoint 2013 (with the one tweak described above)
Add-in part for setting configuration values
The add-in also includes an add-in part (deployed to and rendered from the add-in web) that allows users to enable/disable the header/footer and set the text and colors:
When the add-in part loads, it uses JavaScript to query the property bag of the host web to see if these settings already exist and if so, prepopulates the values in the form. Once the user has made the necessary changes, clicking Set Values will save the changes back to the property bag (again, using JavaScript).
NOTE: The need for our add-in to read and write data to and from the host web property bag requires us to request the FullControl permission at the Web scope in our add-in manifest (AppManifest.xml):
What about MDS?
SharePoint 2013 introduced the Minimal Download Strategy (MDS), which reduces page load time by sending only the differences when users navigate to a new page. While this is a wonderful benefit, it wreaks havoc with solutions that need to manipulate the DOM every time a new page is loaded. In other words, our header and footer may render perfectly on the home page when we first load it, but thanks to MDS when we navigate to the “Documents” library, only part of the page will actually be re-rendered. Our header and footer will not display properly (if at all) when only part of the page is re-rendered to support a new page request.
For much deeper reading on this subject, I encourage you to go through Wictor Wilen’s blog posts introducing the MDS and explaining the correct way to execute JavaScript functions on MDS-enabled sites. My code is based on Wictor’s solution and works properly in scenarios where MDS is enabled and where it is not (e.g., on Publishing sites or any site where the MDS feature has been deactivated).
We handle MDS by calling RegisterModuleInit() with the function we need to execute on every page load in HeaderFooter.js:
if (typeof _spPageContextInfo != "undefined" && _spPageContextInfo != null) { // MDS enabled RegisterModuleInit(_spPageContextInfo.siteServerRelativeUrl + 'Style Library/Headerfooter.js', DJ.HeaderFooter.Render.initializeHeaderFooter); } // Run now on this page (and non-MDS scenarios) DJ.HeaderFooter.Render.initializeHeaderFooter();
The code
I have posted the code for this add-in to GitHub at the following location:
https://github.com/dannyjessee/SiteHeaderFooter
I encourage you to download it, try it out in your environment, and let me know if you run into any issues with it. My sincere thanks go out to Chris O’Brien, Randy Drisgill, and Wictor Wilen for giving me the building blocks needed to put this add-in together.
- Our footer