Question
Angular NgModule Exports: Use a Component from Another Module
Question
In an Angular 2 application generated with Angular CLI, TaskCardComponent works when it is declared directly in AppModule. After moving it into TaskModule, how can BoardComponent, which is declared in AppModule, use <task-card>?
AppModule imports TaskModule, and TaskModule declares TaskCardComponent:
@NgModule({
declarations: [
AppComponent,
BoardComponent,
LoginComponent,
PageNotFoundComponent
],
imports: [
BrowserModule,
FormsModule,
HttpModule,
TaskModule
],
bootstrap: [AppComponent]
})
export class AppModule {}
@NgModule({
declarations: [TaskCardComponent],
imports: [MdCardModule]
})
export class TaskModule {}
What must be added or changed so that TaskCardComponent can be used in BoardComponent's template?
Short Answer
You will learn how Angular module visibility works. A component belongs in exactly one module's declarations; to make it available to components in other modules, its module must list it in exports, and the consuming module must list that module in imports.
Concept
Angular uses NgModule metadata to determine which directives, components, and pipes are valid inside a component template.
declarationsregister components, directives, and pipes that belong to one module.exportsdefine the public template API of a module.importsbring another module's exported template API into the current module.
Declaring TaskCardComponent in TaskModule makes it available to templates declared inside TaskModule. It does not automatically make it visible to BoardComponent, because BoardComponent belongs to AppModule.
AppModule already imports TaskModule, so the missing step is to export TaskCardComponent from TaskModule.
A declarable—component, directive, or pipe—must be declared by one and only one Angular module. Do not add TaskCardComponent to both TaskModule and declarations.
Mental Model
Think of an Angular module as a workshop.
declarationsare the tools owned and used inside that workshop.exportsare the tools placed on a shared counter for other workshops.importsare the shared counters that a workshop can access.
TaskModule owns TaskCardComponent. Even though AppModule visits TaskModule through imports, it can only use the items that TaskModule puts on its shared counter with exports.
Syntax and Examples
The standard pattern is:
@NgModule({
declarations: [FeatureComponent],
exports: [FeatureComponent]
})
export class FeatureModule {}
Then import that feature module wherever its exported component is needed:
@NgModule({
declarations: [PageComponent],
imports: [FeatureModule]
})
export class AppModule {}
For this application, update TaskModule:
import { NgModule } from '@angular/core';
import { MdCardModule } from '@angular2-material/card';
import { TaskCardComponent } from './task-card/task-card.component';
@NgModule({
declarations: [TaskCardComponent],
imports: [],
: []
})
{}
Step by Step Execution
Consider these modules:
@NgModule({
declarations: [TaskCardComponent],
exports: [TaskCardComponent]
})
export class TaskModule {}
@NgModule({
declarations: [BoardComponent],
imports: [TaskModule]
})
export class AppModule {}
And this template:
<task-card></task-card>
Angular processes it conceptually as follows:
BoardComponentis declared byAppModule.- Angular checks
AppModule's template scope when compilingBoardComponent's template. AppModuleimportsTaskModule.- Angular reads
TaskModule'sexportslist.
Real World Use Cases
Module exports are useful whenever a feature provides reusable UI:
- A
SharedModuleexports buttons, dialogs, loading indicators, and formatting pipes used across pages. - A
TasksModuleexports a task card and task list used by a board page and a dashboard page. - An
AuthModuleexports a login form while keeping internal helper components private. - A design-system module exports approved UI controls so teams use consistent components.
Export only what another module truly needs. Internal implementation components can remain declared but unexported.
Real Codebase Usage
In larger Angular applications, developers commonly organize code by feature and expose a small public API from each feature module.
@NgModule({
declarations: [TaskCardComponent, TaskEditorComponent, TaskStatusPipe],
imports: [CommonModule],
exports: [TaskCardComponent, TaskStatusPipe]
})
export class TasksModule {}
Here, other modules can use TaskCardComponent and TaskStatusPipe, but TaskEditorComponent remains an internal detail.
Common patterns include:
- Feature modules: Declare feature-specific components and export only reusable ones.
- Shared UI modules: Export common presentational components, directives, and pipes.
- Lazy-loaded modules: Import the shared module directly in each lazy feature that needs its exports; do not assume imports from
AppModuleare globally visible. - Service configuration: Put application-wide singleton services in a root-level provider configuration rather than exporting components for that purpose.
For modern standalone Angular components, template dependencies are listed directly in a component's imports. The same visibility principle still applies: a template can only use dependencies that it imports or that are exported by an imported module.
Common Mistakes
Declaring a component in two modules
This is invalid:
@NgModule({ declarations: [TaskCardComponent] })
export class AppModule {}
@NgModule({ declarations: [TaskCardComponent] })
export class TaskModule {}
Angular will report that the component is declared by more than one module. Declare it once, in its owner module, then export it.
Importing a module but forgetting to export its component
This does not expose TaskCardComponent outside TaskModule:
@NgModule({
declarations: [TaskCardComponent]
})
export class TaskModule {}
Fix it with:
exports: [TaskCardComponent]
Using the class name instead of the selector
Templates use the component selector, not the TypeScript class name:
Comparisons
| Angular metadata | Purpose | Makes a component usable in another module's templates? |
|---|---|---|
declarations | Assigns a component, directive, or pipe to its owning module | No |
imports | Uses exports from another module | Yes, when the other module exports the item |
exports | Publishes declared or imported template items to importing modules | Yes |
providers | Registers injectable services | No; services are not template elements |
declarations and exports are often confused:
- Use
declarationsbecause the module owns a component. - Use
exportsbecause another module should be allowed to use it.
Cheat Sheet
// Feature module: owns and shares a component
@NgModule({
declarations: [TaskCardComponent],
exports: [TaskCardComponent]
})
export class TaskModule {}
// Consumer module: uses the shared component in its declared templates
@NgModule({
declarations: [BoardComponent],
imports: [TaskModule]
})
export class AppModule {}
Rules:
- Declare every non-standalone component, directive, and pipe in exactly one module.
- Export a declaration when another module's templates need it.
- Import the exporting module into every consuming module.
- Use the component's
selectorin HTML. providersmake services injectable; they do not expose components.- A module's imports are not automatically available to unrelated or lazy-loaded modules.
FAQ
Why is my Angular component not a known element after importing its module?
Usually the component is declared but not exported by the imported module. Add it to that module's exports array.
Should I declare TaskCardComponent in both TaskModule and AppModule?
No. A component can belong to only one NgModule. Declare it in TaskModule, export it there, and import TaskModule in AppModule.
Does importing a module make all of its declarations available?
No. It makes only that module's exported declarations available to the importing module's templates.
Do I need to export a component to use it inside the same module?
No. Components declared in the same module can use one another without exports.
Is providers needed to use a component in a template?
No. providers are for dependency injection services. Component template visibility uses declarations, imports, and exports.
What selector should I put in BoardComponent HTML?
Use the value of TaskCardComponent's , such as for .
Mini Project
Description
Create a small reusable task UI module. A board page will render several task cards, demonstrating how a feature module exposes a reusable component to another module.
Goal
Display task titles in BoardComponent by exporting TaskCardComponent from TaskModule.
Requirements
Requirement 1
Keep learning
Related questions
@Directive vs @Component in Angular: Differences, Use Cases, and When to Use Each
Learn the difference between @Directive and @Component in Angular, including use cases, examples, and when to choose each.
Accessing Input Value from EventTarget in TypeScript
Learn why EventTarget has no value property in TypeScript and safely read values from HTML input events in Angular applications.
Angular (change) vs (ngModelChange): What’s the Difference?
Learn the difference between Angular (change) and (ngModelChange), when each fires, and which one to use in forms and inputs.