In an Angular standalone component, what does the @Component imports array do, and what happens if a used child component is missing from it?
answer
- template compilation scope
- standalone implied since v19
- element vs attribute selector failure
- unknown-element diagnostic at build time
basics
~10 sThe imports array lists the components, directives, pipes and NgModules a standalone component's template may use. A missing element-selector child fails the build with NG8001; a missing attribute-selector child is silently never created.
solid answer
~40 sSince v19 components are standalone by default, so each one declares its own template dependencies in `@Component.imports` instead of relying on an NgModule's `declarations`. The compiler treats that list as the template's scope: only imported components and directives can match selectors, and only imported pipes resolve. It accepts standalone components, directives, pipes, NgModules and arrays of them. If `<app-user-avatar>` is used but not imported, the type-checker reports NG8001 (*not a known element*), plus NG8002 for any input bound on it. If the child has an attribute selector such as `button[app-primary]`, there is no error unless you bind one of its inputs: the button renders as a plain button. Built-in blocks like `@if` need no import; `NgClass` or `DatePipe` do.
code
ts · 19 linesimport { Component } from '@angular/core';
import { DatePipe } from '@angular/common';
import { UserAvatar } from './user-avatar';
@Component({
selector: 'app-comment',
imports: [UserAvatar, DatePipe],
template: `
<app-user-avatar [user]="author" />
@if (edited) {
<small>edited {{ editedAt | date: 'short' }}</small>
}
`,
})
export class Comment {
author = { name: 'Ada' };
edited = true;
editedAt = new Date();
}go deeper
Know that imports lists what the template uses, that standalone is the default now, and that @if needs no import while DatePipe does.
Explain the compilation scope: selectors are matched at build time against imports, which is why NG8001 appears for elements but nothing appears for attribute selectors.
Show you can diagnose a component that silently does not render, and keep imports lists tight when migrating NgModule code to standalone.
Discuss how per-component imports make the dependency graph explicit, which helps tree-shaking, lazy loading and ownership boundaries across large codebases.
## What the `imports` field is In Angular, the `@Component` decorator's `imports` array is the component's **template compilation scope**: the list of components, directives, pipes and NgModules that its template is allowed to use. When the compiler reads the template, it only matches element and attribute selectors against the directives in that list, and it only resolves pipe names against the pipes in that list. Nothing is registered globally, so a component written in another file is invisible to a template until it is imported here. This is the job an NgModule's `declarations` and `imports` used to do for a whole group of components. With **standalone components**, each component carries its own dependency list, which makes the dependency graph explicit and lets the build drop code nobody imports. ## Standalone is the default since v19 Before Angular 19, a component was standalone only if it said `standalone: true`. Since **v19**, `standalone` defaults to `true`, so a component that omits the flag is standalone and may use `imports` directly. A component that is still declared in an NgModule has to say `standalone: false`, and for such a component: - adding `imports` is a compile error: *'imports' is only valid on a component that is standalone.* - its template dependencies come from the NgModule that declares it, not from the decorator. Older code often still spells out `standalone: true`; that is now redundant but harmless. ## What can go in the array | Entry | Example | What it makes available | |---|---|---| | Standalone component | `UserAvatar` | its selector, e.g. `<app-user-avatar>` | | Standalone directive | `NgClass`, `RouterLink` | its attribute or element selector | | Standalone pipe | `DatePipe`, `AsyncPipe` | its pipe name in `{{ x \| date }}` | | NgModule | `CommonModule`, a library module | everything that module exports | | Array of the above | a shared `const` array | each element, flattened | The built-in control-flow blocks (`@if`, `@for`, `@switch`, `@defer`) are **template syntax**, not directives, so they need no import. Their predecessors `NgIf`, `NgForOf` and `NgSwitch` are directives and must be imported; they are deprecated since v20. ## What happens when you forget one The failure depends on what kind of selector the missing dependency has: 1. **Element selector** (`<app-user-avatar>`): the template type-checker reports **NG8001**, *'app-user-avatar' is not a known element*, and the build fails. Binding an input on it (`[user]="u"`) adds **NG8002**, *Can't bind to 'user' since it isn't a known property*. 2. **Attribute selector** (`<button app-primary>`): no error, unless you also bind one of its inputs, which surfaces NG8002 because the input is not a property of `<button>`. Unknown attributes are legal HTML, so the element renders as a plain native element and the component is simply never created. This is the most confusing variant: the page looks almost right. 3. **Pipe** (`{{ d | date }}`): the compiler reports that no pipe with that name was found. 4. **Built-in control flow**: nothing to forget. The rule behind items 1 and 2 is that Angular **matches selectors statically at compile time**, against the scope the `imports` array defines. It never looks a component up at runtime by tag name. ## The reverse mistake: unused imports Importing something the template never uses does no harm at runtime, but it adds noise and compile work. The extended diagnostic **NG8113** (unused standalone imports) warns about it, so a stale `imports` list is easy to clean up. ## Worked example ```ts import { Component } from '@angular/core'; import { DatePipe } from '@angular/common'; import { UserAvatar } from './user-avatar'; @Component({ selector: 'app-comment', imports: [UserAvatar, DatePipe], template: ` <app-user-avatar [user]="author" /> @if (edited) { <small>edited {{ editedAt | date: 'short' }}</small> } `, }) export class Comment { author = { name: 'Ada' }; edited = true; editedAt = new Date(); } ``` Here `UserAvatar` and `DatePipe` must be listed; `@if` needs nothing. Remove `UserAvatar` from the array and the build stops with NG8001; remove `DatePipe` and the pipe cannot be resolved. ## Why interviewers ask it The question checks that a candidate understands the **compilation scope** model rather than a global registry, knows that standalone is the default in current Angular, and can diagnose the silent case where an attribute-selector component was never imported. A good answer names the error the compiler gives and explains why the attribute case gives none.
- Can a standalone component put an NgModule in its imports array?Yes. A standalone component can import an NgModule, and everything that module exports becomes usable in its template. That is how standalone code consumes libraries that still ship NgModules, or `CommonModule` if you want all the common directives and pipes at once, although importing the individual standalone directives and pipes keeps the scope tighter.
- What happens if you add imports to a component marked standalone: false?The compiler rejects it: 'imports' is only valid on a component that is standalone. A non-standalone component gets its template scope from the NgModule that declares it, so its dependencies go into that module's `imports` or `declarations` instead.
- Is an unused entry in imports an error?No, it is a warning. The extended diagnostic NG8113 flags symbols in a component's `imports` that the template never uses. They add noise and compile time, so the fix is simply to delete them.
saying these in an interview costs you the question
- Components are registered globally once declared anywhere in the app.
- You must import NgIf or CommonModule to use an @if block.
- A missing attribute-selector component always produces a compile error.
- Standalone components still need an NgModule to be bootstrapped or used.
- Angular looks components up by tag name at runtime.