Exporting standalone components from Angular libraries
Exporting unrelated standalone components from Angular libraries
Libraries export standalone components, directives, and pipes directly from their public API, usually an index.ts
or public_api.ts
file:
libs/our-lib/src/index.ts
export * from "./lib/our-button.component";
export * from "./lib/our-checkbox.component";
Standalone components consuming the library import the components through their imports
array:
rocket.component.ts
import { Component } from "@angular/core";
import { OurButtonComponent } from "@our-org/our-lib";
import { RocketService } from "./rocket.service";
@Component({
imports: [OurButtonComponent],
standalone: true,
template: `<our-button (click)="onRocketLaunch()">Launch rocket</our-button>`,
})
export class RocketComponent {
#rocket: RocketService;
constructor(rocket: RocketService) {
this.#rocket = rocket;
}
onRocketLaunch(): void {
this.#rocket.launch();
}
}
Interoperability with NgModules
Classic components add standalone components they depend on to their declaring NgModule's imports
array:
rocket.component.ts
import { Component, NgModule } from "@angular/core";
import { OurButtonComponent } from "@our-org/our-lib";
import { RocketService } from "./rocket.service";
@Component({
template: `<our-button (click)="onRocketLaunch()">Launch rocket</our-button>`,
})
export class RocketComponent {
#rocket: RocketService;
constructor(rocket: RocketService) {
this.#rocket = rocket;
}
onRocketLaunch(): void {
this.#rocket.launch();
}
}
@NgModule({
declarations: [RocketComponent],
exports: [RocketComponent],
imports: [OurButtonComponent],
})
export class RocketModule {}
Exporting cohesive standalone components from Angular libraries
In case multiple components, directive, and pipes are always used together, we export them in an immutable array from our library's public API:
libs/our-lib/src/index.ts
import { OurTableCellComponent } from "./lib/table/our-table-cell.component";
import { OurTableRowComponent } from "./lib/table/our-table-row.component";
import { OurTableComponent } from "./lib/table/our-table.component";
// (Optionally) export the individual types for selective importing and
// referencing instances for queries and similar purposes
export OurTableCellComponent;
export OurTableRowComponent;
export OurTableComponent;
// Export cohesive standalone declarables for easy importing
export const ourTableDeclarables = [
OurTableCellComponent,
OurTableRowComponent,
OurTableComponent,
] as const;
Standalone components consuming the library import the components through their imports
array:
data-grid.component.ts (standalone)
import { AsyncPipe } from "@angular/common";
import { Component } from "@angular/core";
import { ourTableDeclarables } from "@our-org/our-lib";
import { DataGridService } from "./data-grid.service";
@Component({
imports: [AsyncPipe, ourTableDeclarables],
standalone: true,
template: `
<our-table>
<our-table-row *ngFor="let row of rows$ | async">
<our-table-cell *ngFor="let cell of row.cells">
{{ cell.text }}
</our-table-cell>
</our-table>
`,
})
export class DataGridComponent {
rows$ =
constructor(dataGridService: DataGridService) {
this.rows$ = dataGridService.rows$;
}
}
Interoperability with NgModules
Classic components depending add the exported standalone declarables to their NgModule's imports
array:
data-grid.component.ts (classic)
import { AsyncPipe } from "@angular/common";
import { Component, NgModule } from "@angular/core";
import { ourTableDeclarables } from "@our-org/our-lib";
import { DataGridService } from "./data-grid.service";
@Component({
standalone: false,
template: `
<our-table>
<our-table-row *ngFor="let row of rows$ | async">
<our-table-cell *ngFor="let cell of row.cells">
{{ cell.text }}
</our-table-cell>
</our-table>
`,
})
export class DataGridComponent {
rows$ =
constructor(dataGridService: DataGridService) {
this.rows$ = dataGridService.rows$;
}
}
@NgModule({
declarations: [DataGridComponent],
exports: [DataGridComponent],
imports: [AsyncPipe, ourTableDeclarables]
})
export class DataGridModule {}