Add a Header Image to a Modern Page
We’re always trying to experiment with what’s possible with branding SharePoint. As one of the developers on the PixelMill team, I knew it was long overdue to try my hand at playing with the relatively new custom header and footer available in modern pages through custom SharePoint Framework (SPFx) Extensions. I decided to see if I could mimic a branded header bar by adding a logo into the header that would link back to the home page.
Prereqs
If you’re brand new to SPFx as I was, you’ll definitely want to head over to the good folks at Microsoft, who have lots of guided tutorials and videos to get you started. At the very least, you should:
- Set up your O365 tenant and development environment
- Work through the Build your first SharePoint Framework Extension tutorial
- Work through the Use page placeholders from Application Customizer tutorial — This is our starting point!
Let’s do this!
At this point, your extension makes use of the Top and Bottom placeholders in modern pages to inject HTML. The header and footer content are defined by the properties passed to the query string parameters:
/sites/TeamSite?loadSPFX=true&debugManifestsFile=
https://localhost:4321/temp/manifests.js&
customActions={%22459e9d09-3ced-4486-8f80-6c2c92cc49b6%22:{%22location%22:%22ClientSideExtension.ApplicationCustomizer%22,%22properties%22:{%22Top%22:%22Top%20area%20of%20the%20page%22, %22Bottom%22:%22Bottom%20area%20in%20the%20page%22}}}
Those properties would be a pretty handy way to pass in an image URL so that you wouldn’t have to hard-code the image URL into the injected code. So that’s exactly what we’ll do!
In the rest of this tutorial, we will:
- Add the image to the site assets,
- Modify the code to pass in the image URL, and
- Modify the rendered HTML code and CSS to display the image and link to the home page
First, upload the image you’d like to use into the Documents > Site Assets folder of your site (or really, any other location where you’d like to keep your image). Make a note of the image location URL.
Fire up your code editor to modify your previously-created HelloWorld extension.
Open src/extensions/helloWorld/HelloWorldApplicationCustomizer.ts. Look for the section where you define the IHelloWorldApplicationCustomizerProperties.
Add a new line for the Logo:
1 2 3 4 5 | export interface IHelloWorldApplicationCustomizerProperties { Top: string; Bottom: string; Logo: string; } |
Now look for the section where the top placeholder is set:
In the code below, I’ve added a logoString variable to hold the Logo property, then modified the HTML to add a link to the site home page, the image itself, and the original top text standing in for the image ALT attribute.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | if (this.properties) { let topString: string = this.properties.Top; if (!topString) { topString = '(Top property was not defined.)'; } let logoString: string = this.properties.Logo; if (!logoString) { console.error('Logo URL was not defined.'); } if (this._topPlaceholder.domElement) { this._topPlaceholder.domElement.innerHTML = ` <div class="${styles.app}"> <div class="ms-bgColor-themeDark ms-fontColor-white ${styles.top}"> <div class="${styles.logo}"><a href="${this.context.pageContext.web.absoluteUrl}"><img src="${escape(logoString)}" alt="${escape(topString)}" /></a></div> </div> </div> `; } } |
Now open AppCustomizer.module.scss. Modify this with additional styles to format the image and top bar. I added some padding, removed the height of the top bar, and kept the logo to be 80px or less.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 | .app { .top { text-align:center; line-height:2.5; font-weight:bold; display: flex; align-items: center; justify-content: center; padding: 10px; .logo { max-width: 80px; IMG { max-width: 100%; height: auto; } } } .bottom { height:40px; text-align:center; line-height:2.5; font-weight:bold; display: flex; align-items: center; justify-content: center; } } |
Finally, open /sharepoint/assets/elements.xml and modify the ClientSideComponentProperties to add in the Logo property:
1 | ClientSideComponentProperties="{"Top":"Alt text for image","Bottom":"Bottom area in the page","Logo":"https://yourtenant.sharepoint.com/:i:/r/sites/TeamSite/SiteAssets/icon.png"}"> |
How it looks
If you don’t already have gulp running, go ahead and run gulp serve –nobrowser.
Then, open up a modern page and append this to the URL (don’t forget to replace the application ID with your own from the HelloWorldApplicationCustomizer.manifest.json and to link in your own logo image location):
1 | ?loadSPFX=true&debugManifestsFile=https://localhost:4321/temp/manifests.js&customActions={"459e9d09-3ced-4486-8f80-6c2c92cc49b6":{"location":"ClientSideExtension.ApplicationCustomizer","properties":{"Top":"Alt%20text%20for%20image","Bottom":"Bottom%20area%20in%20the%20page","Logo":"https://yourtenant.sharepoint.com/:i:/r/sites/TeamSite/SiteAssets/icon.png"}}} |
Click “Load debug scripts” to allow the script to run locally.
And you’ll see your image, linking to the home page, in the top header!
Now what?
You might be wondering how this would all deploy to SharePoint. I would suggest that you continue with the tutorials at Microsoft, starting from Deploy your Extension to SharePoint. One thing you’ll notice, though, is that there is no current interface for setting those Extension properties — you just install the solution as-is. What if you want to change the image location for some sites?
That’s where this handy PnP-Powershell command comes in: Add-PnPCustomAction. You can try doing something like this while connected to your SharePoint site in Powershell:
1 | Add-PnPCustomAction -Name "HelloWorldCustomAction" -Title "HelloWorld" -Location "ClientSideExtension.ApplicationCustomizer" -ClientSideComponentId "459e9d09-3ced-4486-8f80-6c2c92cc49b6" -ClientSideComponentProperties "{"Top":"Alt%20text%20for%20image","Bottom":"Bottom%20area%20in%20the%20page","Logo":"https://yourtenant.sharepoint.com/:i:/r/sites/TeamSite/SiteAssets/icon.png"}}" |
Use with caution!
Unfortunately, it looks like my pretty image logo and visions of a fully branded and functional header are going to need to go back to the drawing board. While I’ve demonstrated that it’s possible to add some branding to the top of a Modern site, doing so effectively reduces the usable, scrollable section of the page. This becomes especially evident on a document library page:
While having the Top and Bottom placeholders are exciting, it will definitely take some good UX + UI work to make best use of the limited space. Our designers are already dreaming of some different things to try for upcoming Modern projects! If you’ve been coming up with some creative uses for the Top and Bottom placeholders, we’d love to hear about it in the comments below!
Hi Corrie!
Thank you for this.
You are obviously the only one in the whole world, giving an example on this right now. But I can’t get it to work…
What about the “>” character ending the ClientSideComponentProperties string, should it not be “>” as there is no corresponding “<” to it but a “<".
I also had to replace the escape character for ampersand with just "&" in the loadSPFX link to get the script recognized at all by my browser.
(Of this I am sure).
Moreover, what about the "/:i:/r/" in the Logo path? I do not have this in my path, should it be there for a reason?
I have tested changing all these things back an forth…still not working, always:
Error: Script error for "https://localhost:4321/temp/manifests.js" http://requirejs.org/docs/errors.html#scripterror
Hope you can sort out some things…
Hi again
Actually it is all working, after I reverted back to the original “starting point” project
and did all this once again. Only thing needed for me was replacing the ampersand escape character (“&”) with just “&” (in the ?loadSPFX string), otherwise all paths or so was just as-is.
However, when deploying, it was picky about the ClientSideComponentProperties string, where I had to replace all “”” with
its escape character “"”.