Angular has become one of the most popular frameworks to build web applications today.
One of the key features of the framework is its component-based architecture, which allows best practices like modularity and reusability. Each Angular component consists of a template, a TypeScript class and metadata.
In this blog post, we will dive deeper into standalone components, and we will explore the anatomy of an application based on them.
For the demo application, we will create a card-like component which can be used to render blog posts in a web application.
Prerequisites
You'll need to have installed the following tools in your local environment:
- The latest LTS version of Node.js is recommended.
- Either NPM or Yarn as a package manager.
- The Angular CLI tool(Command-line interface for Angular).
Initialize the Project
Let's create a project from scratch using the Angular CLI tool:
ng new demo-angular-standalone-components --routing --prefix corp --style css --skip-tests
This command will initialize a base project using some configuration options:
--routing
. It will create a routing module.--prefix corp
. It defines a prefix to be applied to the selectors for created components(corp
in this case). The default value isapp
.--style css
. The file extension for the styling files.--skip-tests
. Disable the generation of testing files for the new project.
If you pay attention to the generated files and directories, you'll see an initial project structure including the main application module and component:
|- src/
|- app/
|- app.module.ts
|- app-routing.module.ts
|- app.component.ts
Creating Standalone Components
First, let's create the custom button to be used as part of the Card component later. Run the following command on your terminal:
ng generate component button --inline-template --standalone
It will create the files for the component. The --standalone
option will generate the component as standalone.
Let's update the button.component.ts
file using the content below.
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'corp-button',
standalone: true,
imports: [CommonModule],
template: `
<button class="corp-button">
<ng-content></ng-content>
</button>
`,
styleUrls: ['./button.component.css']
})
export class ButtonComponent {
}
Pay attention to this component since it's marked as standalone: true
.
Starting with Angular v15: components, directives, and pipes can be marked as standalone by using the flag standalone
.
When a class is marked as standalone, it does not need to be declared as part of an NgModule
. Otherwise, the Angular compiler will report an error.
Also, imports
can be used to reference the dependencies.
The imports property specifies the standalone component's template dependencies — those directives, components, and pipes that can be used within its template. Standalone components can import other standalone components, directives, and pipes as well as existing NgModules.
Next, let's create the following components: card-title
, card-content
, card-actions
and card
.
This can be done at once using the next commands.
ng generate component card-title --inline-template --standalone
ng generate component card-content --inline-template --standalone
ng generate component card-actions --inline-template --standalone
ng generate component card --inline-template --standalone
On card-title.component.ts
file, update the content as follows:
//card-title.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'corp-card-title',
standalone: true,
imports: [CommonModule],
template: `
<h4>
<ng-content></ng-content>
</h4>
`,
styleUrls: ['./card-title.component.css']
})
export class CardTitleComponent {
}
Next, update the card-content.component.ts
file:
//card-content.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'corp-card-content',
standalone: true,
imports: [CommonModule],
template: `
<p class="corp-card-content">
<ng-content></ng-content>
</p>
`,
styleUrls: ['./card-content.component.css']
})
export class CardContentComponent {
}
The card-actions.component.ts
file should have the content below:
// card-actions.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'corp-card-actions',
standalone: true,
imports: [CommonModule],
template: `
<div class="corp-card-actions">
<ng-content></ng-content>
</div>
`,
styleUrls: ['./card-actions.component.css']
})
export class CardActionsComponent {
}
Finally, the card.component.ts
file should be defined as follows:
//card.component.ts
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
@Component({
selector: 'corp-card',
standalone: true,
imports: [CommonModule],
template: `
<div class="corp-card">
<ng-content></ng-content>
</div>
`,
styleUrls: ['./card.component.css']
})
export class CardComponent {
}
Using Standalone Components
Once all Standalone components are created, we can use them without the need to define an NgModule
.
Let's update the app.component.ts
file as follows:
// app.component.ts
import { Component } from '@angular/core';
import { ButtonComponent } from './button/button.component';
import { CardComponent } from './card/card.component';
import { CardTitleComponent } from './card-title/card-title.component';
import { CardContentComponent } from './card-content/card-content.component';
import { CardActionsComponent } from './card-actions/card-actions.component';
@Component({
selector: 'corp-root',
standalone: true,
imports: [
ButtonComponent,
CardComponent,
CardTitleComponent,
CardContentComponent,
CardActionsComponent
],
templateUrl: './app.component.html',
styleUrls: ['./app.component.css']
})
export class AppComponent {
title = 'demo-angular-standalone-components';
}
Again, this Angular component is set as standalone: true
and the imports
section specifies the other components created as dependencies. Then, we can update the app.component.html
file and use all the standalone components.
<!-- app.component.html -->
<h2>Latest Posts</h2>
<corp-card>
<corp-card-title>Introduction to Angular</corp-card-title>
<corp-card-content>
Angular is a component-based framework for building scalable web applications.
</corp-card-content>
<corp-card-actions>
<corp-button>View</corp-button>
</corp-card-actions>
</corp-card>
<corp-card>
<corp-card-title>Introduction to TypeScript</corp-card-title>
<corp-card-content>
TypeScript is a strongly typed programming language that builds on JavaScript, providing better tooling at any scale.
</corp-card-content>
<corp-card-actions>
<corp-button>View</corp-button>
</corp-card-actions>
</corp-card>
This may not work yet, since we need to configure the Angular application and get rid of the autogenerated module defined under the app.module.ts
file.
Bootstrapping the Application
Angular provides a new API to use a standalone component as the application's root component.
Let's update the main.ts
file with the following content:
// main.ts
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
bootstrapApplication(AppComponent);
As you can see, we have removed the previous bootstrapModule
call and the bootstrapApplication
function will render the standalone component as the application's root component. You can find more information about it here.
Live Demo and Source Code
Want to play around with this code? Just open the Stackblitz editor or the preview mode in fullscreen.
Conclusion
We’re now ready to use and configure the Angular components as standalone and provide a simplified way to build Angular applications from scratch. Do not forget that you can mark directives and pipes as standalone: true
. If you love Angular as much as we do, you can start building today using one of our starter.dev kits or by looking at their related showcases for more examples.