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 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 

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

Microsoft MVP and PnP Team Member. Independent consultant. Certified SCRUM Master. SharePoint, Office 365 and Dynamics 365 are his favourite toys.

41 Comments

  1. Hello,

    Here to create CSS we are using microsoft predifined classes like ms-compositeHeader, What if they changed this name to some other name.

    Recently i saw this, I have used all claseess and implemented css but with O365 updates classes names are different for same webpart and component

  2. Yashwanth Reply

    Hi I am trying to change the background of the existing footer and was able to do it with css. I am having issues with deployment into the production. This is my first time doing it with custom code.
    Could you please help me?

  3. I know it’s very late but I am hiding top bar using css loaded from my SPFX extension and I am seeing some flickering effect because css is being loaded later on using extension.

    Can you suggest my any other approach to hide top bar without any flickering effect?

    • Hugo Bernier Reply

      I really should update the sample, as it seems it doesn’t work as well anymore. You could possibly look into preloading the resources (if the browser supports it), but given the order in which the extensions get loaded, I doubt it’ll help.

  4. can we inject custom css in sharepoint 2019 modern page?

    • Hugo Bernier Reply

      Extensions are supported on SharePoint 2019 , but the code sample was written for SharePoint Online. You’d have to re-build the project for SPFx 1.4.

  5. In your example, you attach it to “pageUrl”: “https://contoso.sharepoint.com/SitePages/Home.aspx”, My question : Is it possible to attach a CSS to the whole Site(not just a page)

    • Hugo Bernier Reply

      Charles,

      The “pageUrl” is only used to tell the debugger what page to launch on. If you deploy the extension and add it to a site, it will run on the whole site.

      I hope this helps?

      • Is this approach applicable for JavaScript injection as well? Thanks!

      • Hugo Bernier

        Yes, in fact [Sergei Sergeev]() created a sample that does just that: .

        The same rules apply though: changing CSS or any form of HTML manipulation is *not* supported by Microsoft. If you use this approach, limit yourself to the HTML that you own, because Microsoft may change the page structure at any time without warning.

        Good luck!

  6. Hi Bernierh,

    I followed your solution, But i’m getting this following error and the custom css style is not getting applied.

    error:

    Refused to apply style from ‘https://amoghtelkar.sharepoint.com/Style%20Library/custom.css’ because its MIME type (”) is not a supported stylesheet MIME type, and strict MIME checking is enabled.

    • Jose Clua Reply

      I have the same issue. Any solution Bernier? Thanks

  7. Pingback: SharePoint List Formatting Tabs - Tech Daily Chronicle

  8. Ramakishore. Gandi Reply

    Hi Hugo,

    You might have answered this question already, but i couldn’t find my answer anywhere in your FAQ’s. Can i deploy this solution to a site collection level app catalog ? If yes, could you please help me with the required changes need to be done to the solution?

    Appreciate your help.

    Tjhank you,
    Rama

  9. Frank Chen Reply

    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!

  10. 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;
    }

  11. 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

  12. 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

  13. Great article, Hugo.

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

    Thanks

  14. 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?

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

  16. 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.

  17. 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.

  18. Used your 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 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).

How can I help?

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