Standalone components eliminate the need for NgModules, making Angular applications simpler and more modular.
Creating Standalone Components
typescript
import { Component } from '@angular/core';
@Component({
selector: 'app-header',
template: `
<header>
<h1>{{ title }}</h1>
<nav>
<a routerLink="/">Home</a>
<a routerLink="/about">About</a>
</nav>
</header>
`,
standalone: true
})
export class HeaderComponent {
title = 'My App';
}Importing Dependencies
typescript
import { Component } from '@angular/core';
import { CommonModule } from '@angular/common';
import { RouterModule } from '@angular/router';
import { FormsModule } from '@angular/forms';
@Component({
selector: 'app-user-list',
template: `
<div *ngFor="let user of users">
{{ user.name }}
</div>
`,
standalone: true,
imports: [
CommonModule,
RouterModule,
FormsModule
]
})
export class UserListComponent {
users = [...];
}Standalone Services
typescript
import { Injectable } from '@angular/core';
@Injectable({
providedIn: 'root'
})
export class UserService {
constructor(private http: HttpClient) {}
getUsers() {
return this.http.get<User[]>('/api/users');
}
}Bootstrapping Standalone Apps
typescript
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { provideRouter } from '@angular/router';
import { routes } from './app/app.routes';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
provideHttpClient()
]
});Lazy Loading Standalone Components
typescript
export const routes: Routes = [
{
path: 'home',
loadComponent: () =>
import('./home/home.component')
.then(m => m.HomeComponent)
},
{
path: 'admin',
loadComponent: () =>
import('./admin/admin.component')
.then(m => m.AdminComponent)
}
];Feature Modules with Routes
typescript
// app/admin/admin.routes.ts
import { Routes } from '@angular/router';
export const ADMIN_ROUTES: Routes = [
{
path: '',
component: AdminComponent,
children: [
{
path: 'users',
loadComponent: () =>
import('./users/users.component')
.then(m => m.UsersComponent)
},
{
path: 'settings',
loadComponent: () =>
import('./settings/settings.component')
.then(m => m.SettingsComponent)
}
]
}
];typescript
import { ADMIN_ROUTES } from './admin/admin.routes';
export const routes: Routes = [
{
path: 'admin',
loadChildren: () =>
import('./admin/admin.routes')
.then(m => m.ADMIN_ROUTES)
}
];Dependency Injection
typescript
@Component({
selector: 'app-users',
template: `...`,
standalone: true,
imports: [CommonModule],
providers: [UserService] // Component-level providers
})
export class UsersComponent {
constructor(private userService: UserService) {}
}Pipes and Directives
typescript
import { Pipe, PipeTransform } from '@angular/core';
@Pipe({
name: 'truncate',
standalone: true
})
export class TruncatePipe implements PipeTransform {
transform(value: string, limit: number): string {
return value.length > limit
? value.substring(0, limit) + '...'
: value;
}
}Interceptors
typescript
import {
HTTP_INTERCEPTORS,
provideHttpClient,
withInterceptorsFromDi
} from '@angular/common/http';
bootstrapApplication(AppComponent, {
providers: [
provideHttpClient(withInterceptorsFromDi()),
{
provide: HTTP_INTERCEPTORS,
useClass: AuthInterceptor,
multi: true
}
]
});Testing Standalone Components
typescript
import { ComponentFixture, TestBed } from '@angular/core/testing';
describe('UserListComponent', () => {
let component: UserListComponent;
let fixture: ComponentFixture<UserListComponent>;
beforeEach(async () => {
await TestBed.configureTestingModule({
imports: [UserListComponent],
providers: [UserService]
}).compileComponents();
fixture = TestBed.createComponent(UserListComponent);
component = fixture.componentInstance;
fixture.detectChanges();
});
it('should create', () => {
expect(component).toBeTruthy();
});
});Migration Strategy
Gradually migrate to standalone:
- 1Start new features as standalone
- 2Convert leaf components first
- 3Move up the component tree
- 4Remove NgModules last
Standalone components simplify Angular development while maintaining all the framework's powerful features.