Why would you want to inject CSS?

Since Microsoft introduced Modern Pages to Office 365 and SharePoint, it is really easy to create beautiful sites and pages without requiring any design experience.

If you need to customize the look and feel of modern pages, you can use custom tenant branding, custom site designs, and modern site themes without incurring the wrath of the SharePoint gods.

If you want to go even further, you can use SharePoint Framework Extensions and page placeholders to customize well-known areas of modern pages. Right now, those well-known locations are limited to the top and bottom of the page, but I suspect that in a few weeks, we'll find out that there are more placeholder locations coming.

But what happens when your company has a very strict branding guideline that requires very specific changes to every page? When your customization needs go beyond what's supported in themes? When you need to tweak outside of those well-known locations?

Or, what if you're building a student portal on Office 365 and you need to inject a custom font in a page that is specifically designed to help users with dyslexia?

That's when I would use a custom CSS.

Here be dragons!

Before you go nuts and start customizing SharePoint pages with crazy CSS customizations, we need to set one thing straight:

With SharePoint, you should always colour within the lines. Don't do anything that isn't supported, ever. If you do, and you run into issues, you're on your own.

A badly coloured version of the SharePoint logo.
With SharePoint, you should always colour within the lines

Remember that Microsoft is constantly adding new features to SharePoint. The customizations you make with injecting custom CSS may stop working if the structure of pages change.

What's worse, you could make changes to a page that prevents new features from appearing on your tenant because you're inadvertently hiding elements that are needed for new features.

With custom CSS (and a CSS zen master), you can pretty much do anything you want. The question you should ask yourself is not whether you can do it, but whether it is the right thing to do.

Enough warnings! How do I inject custom CSS?

It is very easy. In fact, I'm probably spending more time explaining how to do it than it took me to write the code for this. If you don't care about how it works, feel free to download the source and install it.

Using SharePoint Framework Extensions, you can write code that you can attach to any Site, Web, or Lists. You can control the scope by how you register your extensions in your SharePoint tenant.

With an extension, you can insert tags in the HTML Head element.

I know what you're thinking: we can just insert a STYLE block at in the HEAD element and insert your own CSS. Sure, but what happens when you need to change your CSS? Re-build and re-deploy your extension? Nah!

Instead, how about inserting a LINK tag and point to a custom CSS that's located in a shared location? That way, you can modify the custom CSS in one place.

You can even have more than one custom CSS and use your extension properties to specify the URL to your custom CSS. In fact, you can add more than one extension on a site to combine multiple custom CSS together to suit your needs.

Building your custom CSS injection extension

You too can design a beautiful SharePoint site that looks like this:

sampleresults
I'm really a better designer than this. I just wanted a screen shot that smacks you in the face with a bright red bar and a custom round site icon. It hurts my eyes.
  1. Start by creating your own custom CSS (something better than I did, please). For example, the above look was achieved with the following CSS:
    .ms-compositeHeader {
        background-color: red;
    }
    .ms-siteLogoContainerOuter {
        border-radius: 50%;
        border-width: 3px;
    }
    .ms-siteLogo-actual {
        border-radius: 50%;
    }
  2. Save your custom CSS to a shared location on your SharePoint tenant. For example, you could save it in the Styles Library of your root site collection. You could also add it to your own Office 365 CDN. Make note of the URL to your CSS for later. For example, if you saved your custom CSS as contoso.css in the Styles Library of your tenant contoso.sharepoint.com, your CSS URL will be:
https://contoso.sharepoint.com/Style%20Library/contoso.css

which can be simplified to:

/Style%20Library/custom.css
  1. Create an SPFx extension following the instructions provided in the Build your first SharePoint Framework Extension (Hello World part 1) article. (Hey, why improve what's already perfect?).
  2. Change the props interface that was created for your ApplicationCustomizer class and replace the description property to cssurl. For example, my ApplicationCustomer class is called InjectCssApplicationCustomizer so my props interface is going to be called IInjectCssApplicationCustomizerProperties. Like this:
  1. Change your onInit method to insert a LINK element pointing to your cssurl property.
  1. In your serve.json located in the config folder, change the pageUrl to connect to a page on your tenant. Also change the cssurl property to pass the URL to the custom CSS you created in steps 1-2, as follows:
    1. Test that your extension works by running gulp serve. When prompted to allow debug scripts, select Load debug scripts.

DebugScriptWarning

You can now tweak your custom CSS to suit your needs, continuing to hit refresh until you're happy with the results.

Deploying to your production tenant

When ready to deploy, you need to bundle your solution, upload it to the app catalog, and enable the extension on every site you want to customize.

To make things easy, you can add an elements.xml file in your SharePoint folder and pre-configure your custom CSS URL. Here's how:

  1. In your solution's sharepoint/assets folder, create a new file called elements.xml. If you don't have a sharepoint folder or assets sub-folder, create them.
  2. Paste the code below in your elements.xml:
  1. Make sure to replace the custom action TitleClientSideComponentId to match your own extension. You can find those values in your InjectCssApplicationCustomizer.manifest.json, under id and alias.
  2. Change the ClientSideComponentProperties to point to your CSS URL. Pay attention to URL encode the values (e.g.: a space becomes %20).
  3. Run gulp bundle --ship to bundle your solution/
  4. Run gulp package-solution --ship
  5. Drag and drop the .sppkg file that was created in your sharepoint/solution folder to your tenant's app catalog.

If you selected to automatically deploy to all site collections when building the extension, you're done. If not, you'll need to go to every site and add the extension by using the Site Contents and Add an App links.

Conclusion

You can easily inject custom CSS in every modern page of your SharePoint tenant by using an SPFx extension, but be careful. With great CSS power comes great SharePoint responsibility.

You can get the code for this extension at https://github.com/hugoabernier/react-application-injectcss

I'd love to see what you're doing with your custom CSS. Let me know in the comments what you have done, and -- if you're interested -- share the CSS.

I hope this helps?

Author

Independent consultant. Certified SCRUM Master. SharePoint, Office 365 and Dynamics 365 are his favourite toys.

27 Comments

  1. Hi Bernierh, very interesting post to update the SPO appearance. I have a few questions here:
    1. the extension you created was to inject a custom css to overwrite OOTB css. As SPO is under frequent updates, one day if the css name become to unavailable, the customization relied on those css name will suddenly stop working.
    2: the customization might have a limit for SPO partial rendering. let’s say you have a hub site called hub1 with a few site collection associated with hub site. for example hr1 and it1. If we deploy this solution to hr1 site collection, when navigate back to hub1, the page itself won’t be reload. the changes we did here will be applied to the hub1 because the navigation is using partial rendering instead of reload.

    • Hugo Bernier Reply

      Frank,

      Thanks for your feedback. I’ve tried to answer your questions to the best of my abilities:
      1. You’re absolutely right. That’s why there is a section called “Here Be Dragons!”, which is a medieval warning used to describe dangerous areas. You should *not* inject custom CSS in an ideal situation, but if you must, you should do so knowing that your custom CSS may stop working at any time without any notice.
      2. Very true. The SharePoint Developer community has been asking for ways to get notified about such events, which would help handle such cases. There are a few entries in UserVoice to that effect. Until then, this is a potential side effect.

      Thanks for pointing these out. If you (or anyone else) has ideas on how to solve the issues above, please share with the rest of the class!

  2. riccardo amadi Reply

    I’m injecting custom css to remove the button “Get Mobile App”, thanks for your guide!
    Here’s my css:

    div[class^=”feedback_”]{
    display: none;
    }

  3. pallavee mishra Reply

    Thank you. That was really helpful. Can we inject custom jquery files in a similar way

    • Hugo Bernier Reply

      My pleasure! I guess you could, but I wouldn’t recommend it.

      Don’t tell anyone I said so, but you could use a similar approach to insert

  4. I tried your solution, the CSS does not seem to get loaded. I went through your FAQ, couldn’t solve the problem.
    I went with the root site and site library in the root site to upload custom.css
    I don’t seem to be getting any data under Tenant Wide Extensions. It’s an empty list
    The pre built sppkg gave errors and deployment failed

  5. Great article, Hugo.

    Do you happen to know if this can be used to customise modern document library interfaces also?

    Thanks

  6. This is a great post and I was able to create the extension and deploy successfully. I have a question on css – do you know what elements we can style and what we can’t. I am trying to style modern SharePoint webpart titles and other out of the box elements. It looks like the class name is always changing though. Any thoughts?

    • Hugo Bernier Reply

      Vikas, sorry for the delayed response. React usually appends letters and numbers to CSS class names for each instance of a component to ensure that there are no collisions. You could use the CSS substring-matching selectors, something like:

      div[class^=”myclass-“], div[class*=” myclass-“] {
      // Change your styles here
      }

      I hope this helps?

  7. Pingback: UPDATE: Inject Custom CSS on SharePoint Modern Pages using SPFx Application Extensions – Tahoe Ninjas

  8. Pasqualino Reply

    I followed exactly your directions and your example, it works when I run it locally (gulp serve), but it does not work when I add the package on the site, what am I wrong? The file elements.xml should be right.

    • bernierh Reply

      I think that Microsoft’s point-of-view is that you wouldn’t customize Outlook, Word, or Excel, so why would you customize SharePoint? (I’m not saying I agree, but that’s pretty much the position). That being said, there are valid reasons why you would need to do this, and that’s why the sample was accepted in the SPFx samples.

  9. Hi,

    Thanks for this great post, it worked perfectly !
    Do you think the same extension can be used for several pages of the same site ?

    Thanks in advance for your reply.

    Best regards,
    Patrick

    • bernierh Reply

      Thanks for the kind comments!

      You can apply the extension at the site or tenant level, which would apply to multiple pages.

  10. Used your SPFx extension and it properly injected a reference to my SharePoint-hosted `custom.css` after running `gulp serve`, but, unfortunately, the generated package—which I then deployed—contains no references to my `custom.css` document. Any clues as to the delta?

    • bernierh Reply

      In this particular example, I suggested that you upload the custom.css to your site’s /Style Library folder at the root of your tenant, and name your CSS custom.css. You **can** specify a different path using tools like https://github.com/vman/spfx-extensions-cli to set the cssurl property. I was trying to use an approach that wouldn’t require people to compile the extension every time they wanted to change the CSS. If you’d like an example that includes a CSS in the package (meaning that you’ll have to rebuild and re-deploy every time you want to change the CSS), let me know and I’ll gladly oblige.

      Hope this helps?

      • Thanks Hugo! Apologies, as I should have been clearer with my initial comment. As your extension calls for, I uploaded `custom.css` to my `Style Library` folder.

        My confusion is that in a search of both `/sharepoint/solution/debug` and `/temp/deploy` I find no equivalent references to the the `cssurl` set in `serve.json` (which would be `Style%20Library/custom.css`, as you’ve mentioned).

Leave a Reply to riccardo amadi Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

%d bloggers like this: