Fix: Angular Standalone Component Error — Component is Not a Known Element
Quick Answer
How to fix Angular standalone component errors — imports array, NgModule migration, RouterModule vs RouterLink, CommonModule replacement, and mixing standalone with module-based components.
The Problem
Angular throws a template error for a component that should be available:
Error: 'app-user-card' is not a known element:
1. If 'app-user-card' is an Angular component, then verify that it is included in the '@Component.imports' of this component.
2. If 'app-user-card' is a Web Component then add 'CUSTOM_ELEMENTS_SCHEMA' to the '@Component.schemas' of this component to suppress this message.Or using RouterLink in a standalone component breaks:
Error: Can't bind to 'routerLink' since it isn't a known property of 'a'.Or a directive from Angular Material doesn’t work in a standalone component:
Error: 'mat-button' is not a known element
// or: Can't bind to 'matFormField' since it isn't a known propertyOr migrating from NgModule to standalone components breaks existing functionality:
NullInjectorError: No provider for MatSnackBar!Why This Happens
Angular’s standalone components (introduced in Angular 14, stable in Angular 15+) work differently from module-based components:
- No NgModule injection — standalone components don’t belong to an NgModule. They can’t rely on NgModule imports to make other components/directives available in their template.
- Explicit
importsarray required — every component, directive, or pipe used in a standalone component’s template must be listed in itsimportsarray. CommonModulebroken into smaller pieces —*ngIf,*ngFor,async, and other common directives fromCommonModuleare now available as individual standalone exports (NgIf,NgFor,AsyncPipe) or still viaCommonModule.- Router directives need explicit import —
RouterLink,RouterOutlet,RouterLinkActiveare now standalone directives and must be imported individually or viaRouterModule. - Service providers may need to move — services provided in NgModules may not be available to standalone components unless they’re
providedIn: 'root'or explicitly provided.
Fix 1: Add Components to the imports Array
Every non-HTML element in a standalone component’s template must be imported:
// WRONG — UserCardComponent used in template but not in imports
@Component({
selector: 'app-user-list',
standalone: true,
imports: [], // Empty — UserCardComponent not available
template: `
<app-user-card *ngFor="let user of users" [user]="user" />
`,
})
export class UserListComponent {
users = [];
}
// CORRECT — import everything used in the template
import { NgFor } from '@angular/common';
import { UserCardComponent } from './user-card.component';
@Component({
selector: 'app-user-list',
standalone: true,
imports: [
NgFor, // For *ngFor
UserCardComponent, // For <app-user-card>
],
template: `
<app-user-card *ngFor="let user of users" [user]="user" />
`,
})
export class UserListComponent {
users = [];
}Common Angular built-ins that need importing:
import {
NgIf,
NgFor,
NgClass,
NgStyle,
NgSwitch, NgSwitchCase, NgSwitchDefault,
AsyncPipe,
DatePipe,
DecimalPipe,
CurrencyPipe,
UpperCasePipe, LowerCasePipe,
JsonPipe,
SlicePipe,
} from '@angular/common';
// Or import all of them at once (larger bundle, but convenient during migration)
import { CommonModule } from '@angular/common';New control flow syntax (Angular 17+) doesn’t need imports:
// Angular 17+ built-in control flow — no imports needed
@Component({
standalone: true,
imports: [UserCardComponent], // Only UserCardComponent needed
template: `
@for (user of users; track user.id) {
<app-user-card [user]="user" />
}
@if (isLoading) {
<p>Loading...</p>
}
`,
})
export class UserListComponent {}Fix 2: Fix Router Directives in Standalone Components
RouterLink, RouterOutlet, and RouterLinkActive must be explicitly imported:
// WRONG — RouterLink not imported
@Component({
standalone: true,
imports: [],
template: `
<a routerLink="/home">Home</a>
<a routerLink="/about">About</a>
`,
})
export class NavComponent {}
// CORRECT — import individual router directives
import { RouterLink, RouterLinkActive } from '@angular/router';
@Component({
standalone: true,
imports: [RouterLink, RouterLinkActive],
template: `
<a routerLink="/home" routerLinkActive="active">Home</a>
<a routerLink="/about" routerLinkActive="active">About</a>
`,
})
export class NavComponent {}
// Or import RouterModule for all router directives at once
import { RouterModule } from '@angular/router';
@Component({
standalone: true,
imports: [RouterModule],
template: `
<router-outlet /> <!-- RouterOutlet -->
<a routerLink="/home">...</a> <!-- RouterLink -->
`,
})
export class AppShellComponent {}Fix 3: Import Angular Material Components
Each Angular Material component must be imported individually in standalone components:
// WRONG — Material components not imported
@Component({
standalone: true,
imports: [],
template: `
<mat-card>
<mat-form-field>
<input matInput placeholder="Name" />
</mat-form-field>
<button mat-button>Submit</button>
</mat-card>
`,
})
export class ProfileFormComponent {}
// CORRECT — import each Material module used
import { MatCardModule } from '@angular/material/card';
import { MatFormFieldModule } from '@angular/material/form-field';
import { MatInputModule } from '@angular/material/input';
import { MatButtonModule } from '@angular/material/button';
@Component({
standalone: true,
imports: [
MatCardModule,
MatFormFieldModule,
MatInputModule,
MatButtonModule,
],
template: `
<mat-card>
<mat-form-field>
<input matInput placeholder="Name" />
</mat-form-field>
<button mat-button>Submit</button>
</mat-card>
`,
})
export class ProfileFormComponent {}Create a shared Material imports file to reduce repetition:
// material.imports.ts — shared Material imports
export const MATERIAL_IMPORTS = [
MatCardModule,
MatButtonModule,
MatFormFieldModule,
MatInputModule,
MatTableModule,
MatDialogModule,
MatSnackBarModule,
MatIconModule,
// ... all Material modules your app uses
] as const;
// In any standalone component
@Component({
standalone: true,
imports: [...MATERIAL_IMPORTS, NgIf, RouterLink],
template: `...`,
})
export class MyComponent {}Fix 4: Fix Services Not Available in Standalone Components
Services that were provided via NgModule must be moved to root or explicitly provided:
// PROBLEM — service provided only in a NgModule
@NgModule({
providers: [UserService], // Only available to this module's components
})
export class UserModule {}
// Standalone component can't use UserService (NullInjectorError)
@Component({ standalone: true })
export class ProfileComponent {
constructor(private userService: UserService) {} // NullInjectorError
}
// FIX 1 — make service provided in root
@Injectable({ providedIn: 'root' })
export class UserService { ... }
// Now available everywhere — standalone and module-based
// FIX 2 — provide at the standalone component level
@Component({
standalone: true,
providers: [UserService], // Available to this component and its children
})
export class ProfileComponent {
constructor(private userService: UserService) {}
}
// FIX 3 — provide in bootstrapApplication (for root-level services)
// main.ts
bootstrapApplication(AppComponent, {
providers: [
UserService,
MatSnackBar, // For Material services
provideRouter(routes),
provideHttpClient(),
provideAnimations(),
],
});Fix 5: Bootstrap a Standalone Application
Setting up a fully standalone Angular application:
// main.ts — standalone bootstrap (no AppModule)
import { bootstrapApplication } from '@angular/platform-browser';
import { AppComponent } from './app/app.component';
import { provideRouter } from '@angular/router';
import { provideHttpClient, withInterceptors } from '@angular/common/http';
import { provideAnimations } from '@angular/platform-browser/animations';
import { routes } from './app/app.routes';
import { authInterceptor } from './app/auth.interceptor';
bootstrapApplication(AppComponent, {
providers: [
provideRouter(routes),
provideHttpClient(
withInterceptors([authInterceptor]),
),
provideAnimations(),
// Feature-specific providers
importProvidersFrom(MatSnackBarModule),
],
}).catch(console.error);
// app.routes.ts — lazy loading standalone components
export const routes: Routes = [
{
path: '',
loadComponent: () =>
import('./home/home.component').then(m => m.HomeComponent),
},
{
path: 'users',
loadComponent: () =>
import('./users/user-list.component').then(m => m.UserListComponent),
},
{
path: 'users/:id',
loadComponent: () =>
import('./users/user-detail.component').then(m => m.UserDetailComponent),
},
];Fix 6: Mix Standalone and NgModule Components
During migration, standalone and module-based components can coexist:
// Use a standalone component inside an NgModule
@NgModule({
declarations: [OldComponent],
imports: [
StandaloneComponent, // Import standalone component into NgModule
],
})
export class FeatureModule {}
// Use a module-based component inside a standalone component
@Component({
standalone: true,
imports: [
NonStandaloneModule, // Import entire NgModule into standalone component
// All components/directives exported by NonStandaloneModule become available
],
template: `<app-legacy-component />`,
})
export class NewStandaloneComponent {}Mark a component as standalone:
// Before (module-based)
@Component({
selector: 'app-user-card',
template: `<div>{{ user.name }}</div>`,
})
export class UserCardComponent {}
// @NgModule declares it:
@NgModule({
declarations: [UserCardComponent],
exports: [UserCardComponent],
})
export class SharedModule {}
// After (standalone)
@Component({
selector: 'app-user-card',
standalone: true, // Add this flag
imports: [], // Add needed imports
template: `<div>{{ user.name }}</div>`,
})
export class UserCardComponent {}
// Remove from NgModule declarations — add to imports instead
@NgModule({
imports: [UserCardComponent], // From declarations to imports
exports: [UserCardComponent], // Keep if other modules need it
})
export class SharedModule {}Fix 7: Run Angular’s Standalone Migration Schematic
Angular provides an automated migration tool:
# Migrate the entire project to standalone (Angular 15.2+)
ng generate @angular/core:standalone
# Options:
# --mode=convert-to-standalone — convert components, directives, pipes
# --mode=prune-ng-modules — remove unnecessary NgModules
# --mode=standalone-bootstrap — switch to bootstrapApplication()
# Run each step separately for safety
ng generate @angular/core:standalone --mode=convert-to-standalone
# Review changes, test, then:
ng generate @angular/core:standalone --mode=prune-ng-modules
# Review changes, test, then:
ng generate @angular/core:standalone --mode=standalone-bootstrapStill Not Working?
CUSTOM_ELEMENTS_SCHEMA — if you’re using actual Web Components (not Angular components) in your template, add CUSTOM_ELEMENTS_SCHEMA to suppress the “unknown element” error:
import { CUSTOM_ELEMENTS_SCHEMA } from '@angular/core';
@Component({
standalone: true,
schemas: [CUSTOM_ELEMENTS_SCHEMA], // Allow unknown HTML elements
template: `<my-web-component></my-web-component>`,
})
export class MyComponent {}Peer dependency issues with Angular Material — Angular Material 15+ has standalone support. Earlier versions require importProvidersFrom(MatModule) in providers. Verify your Material version matches Angular version.
provideRouter vs RouterModule.forRoot — in standalone bootstrap, use provideRouter(routes). In NgModule bootstrap, use RouterModule.forRoot(routes). Mixing these causes router to not initialize.
For related Angular issues, see Fix: Angular HTTP Interceptor Not Working and Fix: Angular Signals Not Updating.
Solo developer based in Japan. Every solution is cross-referenced with official documentation and tested before publishing.
Was this article helpful?
Related Articles
Fix: RxJS Not Working — Observable Not Emitting, Memory Leak from Unsubscribed Stream, or Operator Behaving Unexpectedly
How to fix RxJS issues — subscription management, switchMap vs mergeMap vs concatMap, error handling with catchError, Subject types, cold vs hot observables, and Angular async pipe.
Fix: Angular Pipe Not Working — Custom Pipe Not Transforming or async Pipe Not Rendering
How to fix Angular pipe issues — declaring pipes in modules, standalone pipe imports, pure vs impure pipes, async pipe with observables, pipe chaining, and custom pipe debugging.
Fix: Angular HTTP Interceptor Not Working — Requests Not Intercepted
How to fix Angular HTTP interceptors not triggering — provideHttpClient setup, functional interceptors, order of interceptors, excluding specific URLs, and error handling.
Fix: Angular Signals Not Updating — computed() and effect() Not Triggering
How to fix Angular Signals not updating — signal mutations, computed dependency tracking, effect() cleanup, toSignal() with Observables, and migrating from zone-based change detection.