Standalone components in Angular

In Angular, the `standalone: true` option is used to create a standalone component, also known as a custom element. A standalone component is a self-contained web component that can be used outside of an Angular application, without requiring the entire Angular framework.

Here's a breakdown of the standalone: true option, and how it can be used to create a standalone component in Angular:

1 What is standalone: true?

The standalone option is an attribute that can be added to an Angular component's decorator. When this option is set to true, Angular will generate a custom element that can be used outside of the Angular application.

1.1 Use cases for when to use standalone components in Angular

There are several scenarios where using standalone components with the `standalone: true` flag in Angular can be beneficial:

  1. Micro-frontends: In a micro-frontend architecture, each application is composed of multiple independently developed and deployed frontend modules. Standalone components with standalone: true flag can be used to create self-contained UI components that can be deployed independently within each micro-frontend application.
  2. Library development: When building a library of reusable UI components, using the `standalone: true` flag can simplify the library's deployment and reduce the number of dependencies.
  3. Offline-first applications: In applications that need to work offline, using standalone components with `standalone: true` flag can reduce the number of external dependencies that need to be loaded.
  4. Server-side rendering: Standalone components can be used with server-side rendering to generate the HTML markup for a component without needing to load external dependencies.
  5. Legacy browser support: In some scenarios, standalone components can be used to provide fallback support for older browsers that do not support newer features or dependencies.

2 Creating a Standalone Component

To create a standalone component in Angular, there are a couple of things you need to do - follow these steps:

2.1 Generate an angular component

To generate a component in Angular write the following code in a terminal (within your project):

sh
ng g c input --inline-style --inline-template --standalone true

This will generate a component named `InputComponent`. It will also make sure we have inlined HTML and SCSS within the `InputComponent`.

2.2 If you missed generating the component with the standalone flag you can add it to the Component Decorator

First, add the standalone: true option to the component decorator. This tells Angular to generate a custom element that can be used outside of the Angular application.

typescript
import { Component, EventEmitter, Input, Output } from '@angular/core';
import { CommonModule } from '@angular/common';

type InputValue = string | number | undefined;
type InputType = 'text' | 'number' | 'email';

@Component({
  selector: 'app-input',
  standalone: true, // <-----
  imports: [CommonModule],
  template: ``,
  styles: [],
})
export class InputComponent {
}

2.3 Generate a Custom Element

In order to use Angular Elements, we need to install a separate package for that. This can be done by running the following code:

sh
npm install @angular/elements

After installing the package, we can go ahead and generate a custom element by calling the `createCustomElement()` function from the `@angular/elements` package. This function takes the component class as its argument and returns a custom element constructor. In our case, we don't want to run an application separately, so we can decide to create our "empty" application with our own Angular components. To do this, we need to navigate to the `main.ts` file and replace the code there with the following code:

typescript
// main.ts
import { createApplication } from '@angular/platform-browser';
import { createCustomElement } from '@angular/elements';
import { InputComponent } from './app/ui/input/input.component';

(async () => {
  const app = await createApplication({
    providers: [],
  });

  const inputElement = createCustomElement(InputComponent, {
    injector: app.injector,
  });
  customElements.define('dbs-input', inputElement);
})();

2.4 Building and packaging the code

In order for us to actually build, package, and utilize the component from the project, there are a couple of things we need to do. We need to extend the package.json and replace the `build` script and add a `package` script with the following code:

json
"scripts": {
  ...
  "build": "ng build --output-hashing=none --configuration production",
  "package": "cat dist/angular/{runtime,polyfills,main}.js > dist/angular/component-lib.js"
  ...
},

Removing the output hashing from the build will ensure that the files don't receive hashes on their names, meaning, we can easily package the files into one file in this case named `component-lib.js`. The package script will just combine `runtime.js`, `polyfills.js`, and `main.js` into the `component-lib.js` file.

2.5 Using the Custom Element in another application

Finally, the custom element can be used in any HTML page or application, by importing the script file but also by including the custom element's tag name in the HTML.

html
<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <meta http-equiv="X-UA-Compatible" content="IE=edge" />
    <meta name="viewport" content="width=device-width, initial-scale=1.0" />
    <title>Document</title>
  </head>
  <body>
      <dbs-input label="Name" type="text" value="Hello world"></dbs-input>
     <script src="component-lib.js"></script>
  </body>
</html>

3 Benefits of Standalone Components

Using `standalone: true` to create standalone components has several benefits, including:

  • Reusability: Standalone components can be used outside of an Angular application, which makes them more reusable across different applications and frameworks.
  • Interoperability: Standalone components can be used with other web components, allowing developers to mix and match components from different frameworks and libraries.
  • Decoupling: Standalone components provide a way to decouple a component from the rest of the application, which can improve the maintainability and testability of the codebase.
  • Faster Rendering: Standalone components can be faster to render than Angular components, because they don't require the entire Angular framework to be loaded.

Overall, using `standalone: true` to create standalone components is a powerful tool for creating reusable, interoperable, and decoupled components in Angular.

A video demonstration can be found below:

The entire code can be found here