A core UX principle is that the user should get instant feedback about whatever happens in an application. This includes when people are waiting for stuff to load on a website. Going to a site and wait for several seconds (not all live in a first world country with fast internet) can be very confusing because the user is looking at a blank page and isn’t aware of if the page is broken or whether it eventually will load. For this reason, you should always illustrate loading with a loading spinner (or a loading illustration of your choice) to inform the user to…:

In this post, we are to explore four ways to implement spinners in an Angular application and when to use what.
Get the complete demo of how to implement these different spinners here:
1. way: The “before app loads” spinner
Angular applications can take a while to bootstrap, even with optimized technologies such as tree-shaking and bundle optimization. Especially if you are running init code in an app initializer, it can take considerable time before the application components are getting rendered.
For this reason, you should have a vanilla HTML and CSS version of your spinner getting shown upon app loading.

Creating the pre-Angular spinner
For showing a spinner before Angular has loaded we can write HTML inside the app-root tag Angular uses to bootstrap an Application:
The spinner is styled as:
And then the spinner style is added to the global styles.scss file which will make the style global accessible from our index.html file:
2. way: The spinner component
Sometimes you just want to show a spinner without any overlay. This can be just by creating a spinner component based on the previously designed spinner.

Creating the spinner component
This spinner is bootstrap based and is showing an animated spinner.
The spinner component template:
Spinner style is the same as for the pre-Angular spinner and gets imported even though it is in global scope, to make the dependency explicit:
Otherwise, global CSS can be a mess and in my opinion. Components should be self-reliant style-wise, except for something trivial such as the grid system.
3. way: The spinner overlay wrapper component

Sometimes you just want to add a spinner overlay over a specific part of the DOM and leave other parts, such as the navigation bar, clickable. This is done by creating an Angular wrapper component which will create an overlay over the inner HTML and show a spinner in the middle of the screen.
Creating the spinner overlay wrapper component
The spinner overlay wrapper component is used as a wrapper for the spinner and is wrapping other dom tags using ng-content for creating an overlay over these and show a spinner.
The spinner overlay wrapper style:
Voila! That’s all it takes.
4. way: The full-screen spinner overlay service
The spinner overlay service is creating an overlay which is making the screen unclickable. Depending on your needs you sometimes want to disable all interactions of the app, when it is loading, by creating a full-screen overlay.

Creating the spinner overlay service
The spinner overlay service is using the Angular CDK to spawn a new spinner overlay by creating a CDK Portal and attaching it to the CDK overlayref. This post won’t cover how the Angular CDK works, but in short, the Angular CDK is making it easy to show the SpinnerOverlayComponent by adding it to the bottom of the DOM, absolutely positioned.
The spinner overlay service is created like this:
The spinner overlay component is creating a full-screen overlay and wrapping the spinner component.
The styling:
Finally, the component being created dynamically as a CDK portal:
Note that this component needs to be added to the entryComponents
property of the NgModule
that declares this component for Angular to create it dynamically.
Hook into middleware
For avoiding manually coding every time the spinner overlay should be shown this can be hooked into middleware in Angular, such as an HTTP interceptor for showing loading spinner on HTTP request or a Redux store property eg. isLoading property.
Conclusion
In this post we went through four ways to create spinners in your Angular application: raw HTML and CSS pre-Angular spinner, spinner component, spinner overlay wrapper component and spinner CDK overlay service. All four spinners can make sense to use in the same project because they serve a different purpose. Depending on the desired timing and scope of the spinner you now know how to use the right spinner for the right job.
Get the complete demo of how to implement these different spinners here:
Do you want to become an Angular architect? Check out Angular Architect Accelerator.
21 thoughts on “The Four ways to Create Loading Spinners in an Angular App”
Pingback: How to use Feature Toggling in Angular Apps – Christian Lüdemann IT
Pingback: Implementing Dynamic Environments in Angular for Avoiding One Build per Environment – Christian Lüdemann IT
Hello. This is useful thanks. In your portal example I notice your service is supporting some kind of injectable message (public show(message = ”)) etc. How are you getting this onto the actual component’s template?
I’m actually not using that here, but you could just take this message and pass it to the template, if you wanted to show a message while the spinner was showing.
In the SpinnerOverlayService, add an extra line:
const component = this.overlayRef.attach(spinnerOverlayPortal);
(component.instance as any).message = message;
Hi Steven,
I added your extra lines and passed a message as a parameter in the show() function, but I would like to update the message with a % of the tasks being completed, do you have any tips?
Here is a simplyfied version of my code:
ngOnInit() {
this.spinnerOverlayService.show("0%");
const result$ = this.contentService.getContent(['articles', 'pages', 'users']);
result$.pipe(
mergeMap(([finalResult, progress]) => merge(
progress.pipe(
tap((value) => console.log(`${value}% completed`)), //here my service gives me the % of completion of my http calls, now I would like to update the spinner message with this value
),
finalResult
)),
).subscribe(
(res) => {
this.content = res;
this.spinnerOverlayService.hide();
},
(err) => {
console.log('err: ', err);
this.spinnerOverlayService.hide();
}
);
}
Found the answer by myself: just created a property on the class called componentInstance and substituted const component with this.componentInstance, then created a function on the service updateMessage:
public updateMessage(updatedMessage) {
(this.componentInstance.instance as any).message = updatedMessage;
}
Hi Christian. Thank you for your angular-spinners-demo example. I see implementations in the example code for cases 1 and 2 above but not 3 or 4.
Where does the spinner-overlay tag get inserted for using case 4; index.html? Is that all that is need to instantiate the spinner overlay? I am having some trouble with getting that case to display properly.
This is the thing about Angular CDK overlays, you don’t need to write a spinner tag in the template. By creating a CDK portal the provided component will be added in the bottom of the DOM by Angular.
To see all the nitty gritty details of how these are working in an app, check out the demo repo: https://github.com/lydemann/angular-spinners-demo
– Christian
Thanks Christian. I’ve looked through your code pretty thoroughly and only see examples for cases/ways 1 and 2; i.e. pre-angular-loading and upon clicking the Submit button. Is there code that was never checked in from your GIT example project?
Btw, I am going down the path of implementing the HttpInterceptor and trying to figure out a way to turn the CDK implementation on and off upon request and response.
Hi Richard,
All the examples are in the repo: https://github.com/lydemann/angular-spinners-demo
The pre angular spinner is in index.html, spinner component is in shared, wrapper spinner is in shared and CDK spinner overlay is in core folder.
Sounds like a good idea to use HttpInterceptors for that.
Angular beginner here.
I also struggle finding the point where the overlay is shown and hidden in your code. I tried to put overlayService.show() and hide() in the right spots in my code but all I get is either a “Maximum call stack exceeded and the highlighted line is in the SpinnerOverlayComponent.html or a “Host already has a portal attached” error. What did I miss in your code?
Hi! Great post, thank you so much for this. I still felt a bit vague about the concept of attaching a portal as an entry component and your post helped to finally get it 🙂 By the way, I can’t see if you’re mentioning that if you want to create a spinner overlay service (4) and attach a dynamic component as a portal, you have to put the component in the `entryComponents` array in the root module, otherwise Angular cannot create a reference to it in the run-time.
Hi thanks. Good point! I have updated the post with this now.
Hi Christian, Nice post. I am just struggling to enable spinner overlay wrapper component. I cloned your project but it doesn’t disable the page contents.
Dear Sir,
Thank you for a wonderful article. I have gone through your git repository. There is no reference for ‘app-spinner-overlay’ and ‘app-spinner-overlay-wrapper’ custom elements or these components in your code. Could yo please explain how to use case 3 and case 4 with in example.
love you
Pingback: Why I Moved from Protractor to Cypress and the 7 Steps to Cypress E2E Testing Success – Christian Lüdemann
Nicely done!
Hello Sir, Thank you so much for this great content. I just wanted to know one thing that what to do if wanted to add a message with spinner?
Pingback: Angular Loading Screen? 13 Most Correct Answers - Brandiscrafts.com