How to Create Standalone Components in Angular

Originally published at labs.thisdot.co

May 12, 2023 · 5 minutes read · [Angular] [TypeScript]

Angular has become one of the most popular frameworks to build web applications today. One of the key features of the framework is its the component-based architecture, which allows coding best practices as the 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 version available 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 is app.
  • --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 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 appliction’s root component. You can find more information about it here.

Live Demo and Source Code

Wanna play around with this code? Just open the Stackblitz editor or the preview mode in fullscreen.

Feel free to reach out on Twitter if you have any questions. Follow me on GitHub to see more about my work.

tweet Share