Custom modern page header and footer using SharePoint Framework, part 3

This post is part 3 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. I have updated this code a number of times since publishing part 1 back in June. You can follow the history of these updates by reading my earlier posts:

Part 1
Part 2

In this post, I will update my custom header and footer SharePoint Framework extension based on the changes required for RC0 (SPFx 1.2.0) as well as to support the new tenant-scoped deployment option for SharePoint Framework solutions.

Release Candidate now available

Changes are coming fast in the SharePoint Framework world! Last week, Microsoft announced the Release Candidate (RC0) for SharePoint Framework Extensions with SPFx v1.2.0. A few days prior, I noticed some page placeholder names had changed and my extension’s onRender() method was no longer being called:

Sure enough, my suspicions were confirmed in this Github issue and just a few short days later we had a new release candidate!

You can read the details about all of the changes in the RC release notes. Here’s a quick summary of what I needed to do to update my extension project:

1. Update package.json to reflect the updated versions of SPFx dependencies and devDependencies. Mikael Svenson has a great write-up of this process in this blog post. I essentially had to change any dependency on 1.1.1 to 1.2.0 instead.

2. Run gulp –upgrade (dash dash upgrade) to update my project’s config.json file.

3. Update my HeaderFooterApplicationCustomizer.ts to do the following:

– Leverage the updated placeholderProvider.
– Use updated placeholder names Top and Bottom as well as new types PlaceholderName and PlaceholderContent.
– Explicitly call onRender() from my onInit() method.

You can examine all the differences in my code changes here.

Update for tenant-scoped deployment

Even before this week’s RC0 announcement, I knew I already had to do some work to update my extension. While I was attending SharePoint Fest Seattle last month, Microsoft announced the ability to perform tenant-scoped deployments for SharePoint Framework parts and extensions. This is a great update that eliminates the need to manually install the “app” associated with my extension on every site. Instead, when deploying the package to my tenant’s app catalog, I can check a box to automatically make the solution available to all sites within my tenant (or “organization”):

To add support for tenant-scoped deployment, I added the following line to my package-solution.json file:

“skipFeatureDeployment”: true

This marks the solution as being eligible for tenant-scoped deployment. Note that I still left the feature definition present in this file. This enables the solution to still be installed on individual sites via Site Contents > Add an app should the tenant administrator decline to perform a tenant-scoped installation.

Adding the user custom action for the extension in a tenant-scoped deployment

If you check the box labeled Make this solution available to all sites in the organization before pressing Deploy, you will need to manually add the user custom action associated with the extension on any site where you would like the custom header and footer to be rendered on modern pages. If you deploy the extension at tenant scope, it is immediately available to all sites and you do not need to explicitly add the app from the Site Contents screen. However, because tenant-scoped extensions cannot leverage the feature framework, you will need to associate the user custom action with the ClientSideComponentId of the extension manually. This can be accomplished a number of different ways. Some example code using the .NET Managed Client Object Model in a console application is shown below:

using (ClientContext ctx = new ClientContext("https://[YOUR TENANT]"))
    SecureString password = new SecureString();
    foreach (char c in "[YOUR PASSWORD]".ToCharArray()) password.AppendChar(c);
    ctx.Credentials = new SharePointOnlineCredentials("[USER]@[YOUR TENANT]", password);

    Web web = ctx.Web;
    UserCustomActionCollection ucaCollection = web.UserCustomActions;
    UserCustomAction uca = ucaCollection.Add();
    uca.Title = "SPFxHeaderFooterApplicationCustomizer";
    // This is the user custom action location for application customizer extensions
    uca.Location = "ClientSideExtension.ApplicationCustomizer";
    // Use the ID from HeaderFooterApplicationCustomizer.manifest.json below
    uca.ClientSideComponentId = new Guid("bbe5f3fa-7326-455d-8573-9f0b2b015ff9");

    ctx.Load(web, w => w.UserCustomActions);

    Console.WriteLine("User custom action added to site successfully!");

If you decline to check the box to allow tenant-scoped installation when you upload the .sppkg file to the app catalog, the extension will still be available to manually add to any site via Site Contents > Add an app. If you manually add the extension to a site in this way, the user custom action registration will be handled automatically via the feature framework (as it has in the past). No additional code is necessary to register the user custom action in that case.

Version now available!

All of my updated code (RC0 updates and support for tenant-scoped deployment) can be found within my Github repository at: