Question

Angular NgModule Exports: Use a Component from Another Module

typescriptangularangular-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.

  • declarations register components, directives, and pipes that belong to one module.
  • exports define the public template API of a module.
  • imports bring 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 AppModule declarations.

Mental Model

Think of an Angular module as a workshop.

  • declarations are the tools owned and used inside that workshop.
  • exports are the tools placed on a shared counter for other workshops.
  • imports are 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.

Take Quiz

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: [MdCardModule],
  exports: [TaskCardComponent]
})
export class TaskModule {}

Because AppModule imports TaskModule, templates of components declared by AppModule, including BoardComponent, can now use the selector defined by TaskCardComponent:

<!-- board.component.html -->
<task-card></task-card>

The actual element name must match the selector in @Component(...), for example selector: 'task-card'.

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:

  1. BoardComponent is declared by AppModule.
  2. Angular checks AppModule's template scope when compiling BoardComponent's template.
  3. AppModule imports TaskModule.
  4. Angular reads TaskModule's exports list.
  5. TaskCardComponent is exported, so its task-card selector is available in BoardComponent's template.
  6. Angular creates TaskCardComponent when it encounters <task-card>.

Without exports: [TaskCardComponent], step 5 fails and Angular treats <task-card> as an unknown element.

Real World Use Cases

Module exports are useful whenever a feature provides reusable UI:

  • A SharedModule exports buttons, dialogs, loading indicators, and formatting pipes used across pages.
  • A TasksModule exports a task card and task list used by a board page and a dashboard page.
  • An AuthModule exports 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.

Take Quiz

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 AppModule are 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:

<!-- Incorrect unless this is literally the selector -->
<TaskCardComponent></TaskCardComponent>

<!-- Correct when selector is 'task-card' -->
<task-card></task-card>

Forgetting the module import in the consumer

Exporting alone is not enough. The module that declares the consuming component must import the exporting module.

Expecting imports to be transitive

If AppModule imports TaskModule, a separate lazy-loaded ReportsModule cannot automatically use <task-card>. ReportsModule must import TaskModule too.

Comparisons

Angular metadataPurposeMakes a component usable in another module's templates?
declarationsAssigns a component, directive, or pipe to its owning moduleNo
importsUses exports from another moduleYes, when the other module exports the item
exportsPublishes declared or imported template items to importing modulesYes
providersRegisters injectable servicesNo; services are not template elements

declarations and exports are often confused:

  • Use declarations because the module owns a component.
  • Use exports because another module should be allowed to use it.
  • Use imports because the current module needs another module's public declarations.
Take Quiz

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 selector in HTML.
  • providers make 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 selector, such as <task-card></task-card> for selector: 'task-card'.

How does this work with standalone components?

A standalone component lists its template dependencies in its own imports array. It is not added to an NgModule declarations array.

Take Quiz

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

Take Quiz

Keep learning

Related questions

View more