Long promised, now finally found the time to write about loading spinners in Service Portal.

Probably everybody has (or has not ) seen the three small dots in the Service Portal header, when there is work happening in the background.



This is a great way to indicate to the user, that there is still work to do for the browser.

However I personally find, that those dots might not draw the attention you would want, so let's have a look at how you could override those dots with your own loading spinner.


The good news is: this is really, really simple and quick


In the next few steps, I will describe everything that is needed to get a new loading spinner into your portal.

Attached to this blog, there is also an update set containing the exact result of the below described steps.


1. Picking a new loading spinner & uploading the SVG file

There are plenty of great resources out there, where you can create your own loading spinners. A lot of them will be CSS based, but I personally prefer the .svg (Scalable Vector Graphics) spinners since those will allow you to simply upload the new spinner into the Images tables and then use it in your Header Widget with the <img> tag, rather than re-creating all the CSS.


Here are a few resources (in no particular order, though one of my favourites is loading.io).

For the following example, I will use the spin loading image from loading.io.


Click Get SVG and Upload the SVG to the Images [db_image] table with a name of portal-loading-spinner.svg or pick your own name, just remember that you will have to use it in Step 3.


2. Explaining the out of the box loading spinner

The code snippet responsible for rendering the loading spinner is included in the HTML part of the Header Menu widget.

<div class="header-loader" ng-show="loadingIndicator">
    <div class="hidden-xs sp-loading-indicator la-sm">


The sp-loading-indicator class on the inner <div> element refers to the sp-loader.css file, which ships with Service Portal. This is the CSS class, which contains all CSS styles for rendering the three dots. We will get rid of this <div> in a second, but let me talk about the ng-show for the loadingIndicator variable first.

The whole loading spinner <div> is only shown, when the loadingIndicator variable is set to true, but where does this happen?


Have a look at the Client Script part of the widget and you will find the following three lines:

$scope.$on('sp_loading_indicator', function(e, value) {
  $scope.loadingIndicator = value;


By listening to the sp_loading_indicator event, which is again part of Service Portal, the value of the variable will be determined.

In line 2 of that widget, it will initially be populated with the value of that variable within the $rootScope object.

$scope.loadingIndicator = $rootScope.loadingIndicator;


Essentially everything is already prepared for us, we won't have any work on the client side. We just have to make sure, that our new loading spinner (the .svg image), is rendered in the HTML part.


As the Header Menu is an OOTB widget, we will first have to clone the widget, so we are able to edit it. As a reminder: this is a common practice for all OOTB widgets to make sure, that ServiceNow does not override your changes during the next upgrade.


3. Cloning the Header Menu Widget and overriding the loading spinner

Open the Widget Editor (Service Portal -> Service Portal Configuration -> Widget Editor) and select the Header Menu Widget.

Click the Hamburger Menu beside the Save button and Clone the Widget.


You will not have to work in the Client or Server Script, so you can deselect those parts.

In the HTML part, replace the part described in Step 2 (the whole header-loader <div>) with the following snippet:

<div class="header-loader" ng-show="loadingIndicator">
    <div class="hidden-xs la-sm">
      <img src="portal-loading-spinner.svg" class="loading-spinner"/>

Make sure the name of the image is the name of the image you uploaded in Step 1.


Hint: to test your loading spinner, remove the ng-show directive, so that the loading spinner will always be displayed (or change it to ng-hide). Now you can do a right-click + Inspect in your browser and modify padding, margin, sizing etc. to temporarily adjust and test your styling. Once you have your styling all figured out, you can revert the change and adjust the CSS class.


Now we only need a few minor CSS changes. Within the CSS part, add the definition for the class loading-spinner and make some small adjustments to the header-loader class.


Here is the OOTB CSS for the header-loader class:

.header-loader {
  float: left;
  width: 24px;
  position: relative;
  top: 24px;


Change it to the following and add the loading-spinner class:

.header-loader {
  padding: 5px;

.loading-spinner {
  width: 50px;
  height: 50px;



4. Adding the Header Menu to your Portal

The last step is, that you will have to use that new Header Menu in your Portal.

Navigate to your Portal record in the platform view, open the Main Menu that is allocated to your Portal and simply change the Widget reference (or keep it, if you already had your own widget, to which you added the above described changes).


And that's already it! With a few minor changes, we created our own loading spinner.

That's how it will look (I did not add any menu items to my new header menu):




Obviously you could also pick a CSS based spinner. In that case you would have to add the according CSS to the CSS part of the Widget (or CSS include, that should be related to your portal). In my opinion, SVG files are a great alternative to save yourself some work and still keep it light-weight (the spinner used here, has only a size of 3 KB).

Keep browser support in mind, when using SVG files. In general all major browsers support .svg files, only IE8 and below will not be able to render it.


If the new spinner is still not obvious enough, you could certainly take all of this and render it i.e. in a Bootstrap Modal and display it right in the center of the screen  - that will hopefully be sufficient


Credits go out to daniel.conroy and napike who sent me on the right path


Next time, read about integrating a Google Custom Search Engine into your Service Portal!