written for coders favicon image

Angular Standalone Components - When why and how to use them?!

The featured image for the Angular standalone components blog post

With the release of Angular 14, we can now use standalone components in the popular frontend framework. Standalone components are in developer preview since Angular 14 and have been officially released into the stable API from Angular 15. Since components are the building blocks of any Angular application the introduction of standalone components allows for entirely new architectures for your Angular application. You can even go so far as to build an Angular application without any module files, something a lot of developers will welcome with open arms!

Not only can you create isolated components that do not need to be included in any module, but the introduction of standalone Angular components also allows us to lazy load individual components instead of modules. Some very cool and powerful stuff! So let's dive into it and see what Angular standalone components are all about.

Table of content:

What are Angular standalone components?

Angular standalone components are regular Angular components with an additional flag and optionally some dependency declarations so the component can be used without the need for a NgModule. Before Angular version 14 every component needed to be declared in a NgModule otherwise the component would not render and the Angular compiler did not recognize the selector of the component.

Components, directives, and pipes can be standalone in Angular and they provide a simplified way of building Angular applications by reducing the need for NgModules. You can even take it so far as to build the application without a NgModule file. If you have an existing app that already heavily uses NgModules, don't panic! You can simply use the standalone components alongside your code that uses the modules and replace it bit by bit or only in the places where it makes sense for your application needs.

How to create Angular standalone components?

You can turn any component, directive, or pipe into a standalone version of itself by marking it as:

standalone: true

In Angular 14 you need to add this flag yourself and there is no Angular CLI command yet to generate a standalone component. From Angular 15 and beyond you can use this CLI command to generate your standalone component:

ng g component --standalone

You can add the standalone flag to the decorator of components, directives, and pipes. Angular classes market with this flag does not have to be declared in a declarations array inside one of your NgModules, if you do the Angular compiler will throw an error.

In your TypeScrip file this is how to add the standalone flag:

Gist

As you might have noticed in the code snipped above, we also declared an imports array inside the component decorator. Inside this imports array, we can import all the dependencies needed for this standalone component to work. So here you can import other standalone components, pipes, and directives you want to use.

Not all components, directives, and pipes you want to use might have the standalone flag but instead are declared in a module file. In that scenario you can simply import the module into the standalone component and use the components, directives and pipes declared in that module.

Gist

In the above code snipped you can see we import the MatButtonModule directly into our standalone component and can now utilize all the components, directives and pipes declared in the MatButtonModule. The modules you import into your standalone components can de modules from third-party libraries or internal modules from within your own Angular application.

Using standalone components combined with NgModules

In a lot of scenarios, your application already heavily uses NgModules or you still want to use them to partition your code and manage your lazy loading strategy. If this is the case and you want to use Angular standalone components in a NgModule-based application you can! When you use a standalone component inside of an Angular module you need to add it to the imports of the NgModule decorator. Regular components are declared in the declarations array, standalone components are registered in the imports array. Note that this is only necessary if you want to use the standalone component inside a component that is declared in a NgModule.

Gist

Now you know how to use standalone components in a NgModule-based Angular application, let's find out how we can remove NgModules from our app.

Bootstrapping a standalone component

In order to build and run your Angular application without NgModules you need to bootstrap a standalone component instead of a module. By bootstrapping an Angular standalone component you use it as the root component of the application.

Gist

As you can see bootstrapping a standalone component as the root component of your project is really easy! You only need to import it into your main.ts and add it to the bootstrapApplication method as a parameter.

In most cases when you bootstrap your application you want to configure some dependency injections and configure providers and services for global usage within your application. When bootstrapping a standalone component this can be done with an extra parameter object in the bootstrapApplication method:

Gist

When bootstrapping a standalone component it bases its dependency injection on an explicitly configured list of Providers. However, existing libraries may rely on NgModules for configuring their dependency injection. For example, the Angular router uses the RouterModule.forRoot(), helper, to set up routing in an application. You can use existing NgModules in bootstrapApplication via the importProvidersFrom utility:

Gist

Lazy loading Angular standalone components

The Angular router API was updated and simplified to support the lazy loading of standalone components in an easy and convenient way further reducing the need for modules in your Angular application. You can lazy load a standalone component by defining loadComponent in your route configurations:

Gist

Note that the above syntax only works with standalone components, for any other component you still need to import and lazy load the module. With loadChildren you can now declare a set of routes that need to be lazy loaded. This will work as long as all routes resolve to a standalone component. Otherwise, you need to declare it in a module with RouterModule.forChild. To declare a set of standalone components and routes to be lazy load use this syntax:

Gist

Lastly, if we are using an application without a NgModule we need a place to register the routes to our standalone components. This can be done when you bootstrap your standalone component by adding provideRouter() to the providers array of your bootstrap function.

Gist

A benefit of the provideRouter API is that it’s tree-shakable! Bundlers can remove unused features of the router at build time. This will result in a significant reduction in the bundle size of your router code in the application bundle.

Conclusion

With Angular standalone components, we have entered a new era for the Angular framework. It allows us to reduce our initial load, split up components and logic better, improve our lazy loading, and reduce or remove the need for NgModules. There are many advantages to standalone components and I would start using them in your applications and try to go for an architecture where you don't use NgModules anymore.

Make your friends more educated by sharing!