skip to content

Component Authoring

How a component declares itself and its contract: metadata, inputs, outputs and model(), queries, projection, lifecycle, styles and creation from code. Interviewers probe each part.

part ofAngularoverview, primer and where to startread it →
on this pageshow

explore

questions

page 1 of 2

In Angular, how do you declare component inputs with input() and input.required(), and how do they differ from the @Input decorator?

level: juniorimportance: must knowfreq 76%

answer

  1. a function returning a signal
  2. call it to read it
  3. required checked by the compiler
  4. read-only, unlike a decorated field

basics

~10 s

input(default) and input.required<T>() declare inputs as read-only InputSignal fields you read by calling them, and a missing required binding is a compile error. @Input() marks a plain, reassignable property and remains fully supported.

solid answer

~40 s

`input()` declares a signal input: `size = input(40)` is an `InputSignal<number>` you read as `size()`, `input<number>()` without a default is typed `number | undefined`, and `input.required<string>()` has no default and no `undefined` in its type. The parent's binding looks the same as for `@Input()`. Differences: the signal is read-only, so the child cannot overwrite it; derived state can be a `computed()` that follows it automatically; and `undefined` is honest in the type, with no `!` assertion. Both APIs support `alias`, `transform` and required inputs, and a required input the template does not bind fails the build with NG8008. The signal APIs have been stable since v19 and are recommended for new code; `@Input` stays fully supported.

code

ts · 12 lines
ts
import { Component, computed, input } from '@angular/core';

@Component({
  selector: 'app-avatar',
  template: `<img [src]="src()" [width]="size()" [height]="size()" [alt]="label()" />`,
})
export class Avatar {
  readonly src = input.required<string>();
  readonly size = input(40);
  readonly name = input<string>();
  readonly label = computed(() => this.name() ?? 'User avatar');
}

go deeper

for a junior

Declare inputs with input(), input.required() and @Input(), and remember to call a signal input to read it.

for a middle

Explain the typing differences, read-only InputSignal, alias, and that NG8008 catches a missing required binding at build time.

for a senior

Plan a migration from @Input to signal inputs, replacing ngOnChanges code with computed() and handling inputs the child used to reassign.

for a principal

Weigh consistency across a large codebase: when to run the automated migration, and how to keep mixed APIs readable meanwhile.

## Two ways to declare an input An **input** is a property of a component (or directive) that a parent can set from its template with a binding such as `[size]="64"`. Angular offers two APIs for declaring one. **Signal inputs**, the `input()` function from `@angular/core`, are the current recommendation. The `input`, `output` and `model` APIs were marked stable in **v19**: ```ts import { Component, input } from '@angular/core'; @Component({ selector: 'app-avatar', template: `<img [src]="src()" [width]="size()" [alt]="name()" />`, }) export class Avatar { readonly src = input.required<string>(); // InputSignal<string> readonly size = input(40); // InputSignal<number> readonly name = input<string>(); // InputSignal<string | undefined> } ``` **Decorator inputs**, `@Input()` on a class property, are the original API. They remain fully supported and are in most existing codebases: ```ts import { Component, Input } from '@angular/core'; @Component({ selector: 'app-legacy-avatar', template: `<img [src]="src" />` }) export class LegacyAvatar { @Input({ required: true }) src!: string; @Input() size = 40; } ``` The parent's template binding is identical for both: `<app-avatar [src]="user.photo" [size]="64" />`. ## How signal inputs behave - `input(default)` returns an **`InputSignal<T>`**; you read it by **calling** it: `this.size()` in code, `size()` in the template. - Without a default, `input<number>()` is typed `InputSignal<number | undefined>`, because the parent may never set it. - `input.required<T>()` has no default and does **not** include `undefined` in its type. - The signal is **read-only**: there is no `set()` or `update()`, so a child cannot overwrite what its parent bound. A component that must write back uses a model input instead. - Because it is a signal, anything derived from it with `computed()`, and the template itself, updates automatically when the parent binds a new value. - `input()` may only be called in a **class field initializer** of a component or directive; the compiler rejects other call sites because it records inputs statically. ## Required inputs are checked at build time For both APIs, a required input that a parent's template does not bind is a **compile-time** error, **NG8008**: *Required input 'src' from component Avatar must be specified.* A plain static attribute (`src="/u/7.png"`) counts as setting it. ## Side-by-side comparison | | `input()` / `input.required()` | `@Input()` | |---|---|---| | Type of the member | `InputSignal<T>` | the plain value `T` | | Reading | call it: `size()` | property access: `size` | | Required | `input.required<T>()` | `@Input({ required: true })` | | Alias | `input(0, { alias: 'avatarSize' })` | `@Input({ alias: 'avatarSize' })` or `@Input('avatarSize')` | | Transform | `{ transform: fn }` | `{ transform: fn }` | | Child can reassign | no, read-only | yes, any code can assign the field | | Reacting to change | `computed()`, the template, or `ngOnChanges` | `ngOnChanges` or a setter | ## Aliases The `alias` option changes the name used in templates without changing the class member: with `size = input(40, { alias: 'avatarSize' })` the parent writes `[avatarSize]="64"` while the class still reads `this.size()`. The docs advise avoiding aliases in general; they are useful for keeping an old public name during a rename or for avoiding a collision with a native DOM property name. ## Why the signal API is preferred 1. **Type honesty**: an optional input's `undefined` is in the type, and a required one's is not, without the `!` non-null assertion the decorator version needs. 2. **Derivations stay in sync**: `computed(() => this.size() * 2)` recomputes when the parent binds a new size, which removes most `ngOnChanges` code. 3. **No accidental writes**: the child cannot mutate its own input. An automated migration, `ng generate @angular/core:signal-input-migration`, converts `@Input` fields and updates their references, so mixed codebases are common: both APIs work side by side, even in one component.

  • Can the avatar component do this.size.set(64) on a signal input?
    No. `InputSignal` exposes no `set` or `update`, so the call does not compile. Inputs flow from the parent. If the component needs its own writable copy it keeps separate local state, and if it must push a value back to the parent it declares a model input instead.
  • Where does Angular report a required input that a parent forgets to bind?
    At build time. The template type-checker reports NG8008, naming the missing input and the component. A static attribute such as `src="/u/7.png"` counts as a binding. Separately, reading a required signal input before any value arrives, for example in the constructor, throws NG0950 at runtime.
  • Can one component mix @Input fields and input() signals?
    Yes. Both register ordinary inputs, the binding syntax is the same, and the signal-input migration converts fields incrementally. The only difference inside the class is how each is read: property access for the decorator, a call for the signal.

saying these in an interview costs you the question

  • A signal input can be updated from inside the child with set().
  • Required inputs are only checked at runtime when the component renders.
  • The @Input decorator is deprecated and will be removed.
  • You read a signal input as a plain property, without calling it.
  • input() can be called anywhere, such as inside ngOnInit.
open as a page

In an Angular component, what work belongs in the constructor and what belongs in ngOnInit, and why?

level: juniorimportance: must knowfreq 82%

basics

~20 s

The constructor runs when Angular creates the instance, before any parent bindings are applied, so it should only inject dependencies and register setup. ngOnInit runs once after the first input values are set, so input-dependent initialisation belongs there.

open as a page

In an Angular standalone component, what does the @Component imports array do, and what happens if a used child component is missing from it?

level: juniorimportance: must knowfreq 72%

basics

~10 s

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

open as a page

In an Angular component, what does model() declare, and what can a parent template bind to it?

level: juniorimportance: must knowfreq 62%

basics

~20 s

model() declares a writable signal input: the parent can bind a value in, the child can set() or update() it, and Angular adds a <name>Change output so a [( )] binding to a signal or plain property stays in sync.

open as a page

In Angular, how does a child component emit a custom event with output() or @Output and EventEmitter, and how does the parent read its payload?

level: juniorimportance: must knowfreq 74%

basics

~10 s

The child declares rated = output<number>() or @Output() rated = new EventEmitter<number>() and calls rated.emit(value). The parent binds (rated)="save($event)", where $event is exactly the emitted value, not a DOM event.

open as a page

In an Angular component, how do <ng-content> and its select attribute give a card separate header, body and footer slots?

level: juniorimportance: must knowfreq 60%

basics

~10 s

Each <ng-content select="..."> is a compile-time placeholder that receives the host's direct children matching its selector; an <ng-content> without select takes everything unmatched, and without one, unmatched content is not rendered at all.

open as a page

In Angular, what is the difference between a view query such as viewChild() and a content query such as contentChild()?

level: juniorimportance: must knowfreq 64%

basics

~10 s

A view query (viewChild, viewChildren) searches the component's own template; a content query (contentChild, contentChildren) searches the nodes a parent placed between the component's tags. Neither looks inside another component's template.

open as a page

What view encapsulation modes can an Angular component use, which one is the default, and how do they differ?

level: juniorimportance: must knowfreq 64%

basics

~10 s

ViewEncapsulation offers Emulated (the default: compiler-added attributes scope the styles), ShadowDom (a real shadow root), ExperimentalIsolatedShadowDom (a shadow root that also keeps shared styles out) and None (the styles act globally).

open as a page

In Angular code, how do you create a component with ViewContainerRef.createComponent, and where does it end up in the DOM and view tree?

level: middleimportance: must knowfreq 58%

basics

~20 s

Inject or query a ViewContainerRef and call createComponent(ComponentClass, options). Angular inserts the new host view into that container, after its anchor element, and returns a ComponentRef for setting inputs and destroying it; the view is checked and destroyed with its container.

open as a page

In Angular, when should a component react to input changes with ngOnChanges and SimpleChanges, and when with computed() over a signal input?

level: middleimportance: must knowfreq 62%

basics

~20 s

Use computed() over signal inputs to derive state declaratively; it stays current as any input changes. Use ngOnChanges when you need the previous value, the first-change flag, or still have @Input fields, since SimpleChanges carries previousValue, currentValue and firstChange.

open as a page

In Angular, in what order do a component's lifecycle hooks run on first render, and which of them repeat on later checks?

level: middleimportance: must knowfreq 74%

basics

~10 s

First render: constructor, ngOnChanges (if inputs are bound), ngOnInit, ngDoCheck, ngAfterContentInit, ngAfterContentChecked, ngAfterViewInit, ngAfterViewChecked; ngOnDestroy runs once at removal. Later checks repeat ngOnChanges on input change, ngDoCheck and both Checked hooks.

open as a page

In Angular, when would you declare model() instead of an input() plus output() pair, and when is the pair still better?

level: middleimportance: must knowfreq 55%

basics

~20 s

Use model() when the child edits one value the parent mirrors through [( )]; use input() plus output() when the parent must approve changes, the event carries something other than the value, or the input needs a transform.

open as a page

In Angular, why is an @ViewChild result undefined in ngOnInit, and when do decorator and signal query results actually become available?

level: middleimportance: must knowfreq 68%

basics

~20 s

Decorator queries are dynamic by default and resolve just before ngAfterContentInit or ngAfterViewInit; static: true resolves them before ngOnInit but never updates them. Signal queries have no static option and update themselves, so read them reactively.

open as a page

How does Angular's default Emulated view encapsulation scope a component's CSS, and where does that scoping stop?

level: middleimportance: must knowfreq 58%

basics

~20 s

At compile time Angular appends a component-specific attribute selector to every rule; at runtime it stamps _ngcontent on elements the template creates and _nghost on the host. Styles cannot leak out, but global styles still apply inside.

open as a page

In an Angular template, how do you render a component whose class is only known at runtime, and pass it inputs?

level: juniorimportance: should knowfreq 44%

basics

~10 s

Use NgComponentOutlet: <ng-container *ngComponentOutlet="widgetType; inputs: widgetInputs" />. Angular creates the given component class in place, applies the inputs object with setInput on every check, and recreates the instance when the class changes.

open as a page

In Angular, how do you package a standalone component as a custom element with @angular/elements so a plain HTML page can use its tag?

level: juniorimportance: should knowfreq 38%

basics

~20 s

Call createCustomElement(Component, { injector }) from @angular/elements to get a custom-element class, then register it with the browser's customElements.define('tag-name', Class). The injector usually comes from createApplication(), and the tag must differ from the component's selector.

open as a page

In Angular's @Component decorator, how do template and templateUrl differ from styles, styleUrl and styleUrls, and what rules does the compiler enforce?

level: juniorimportance: should knowfreq 55%

basics

~20 s

template holds an inline template and templateUrl points to an HTML file; styles holds inline CSS while styleUrl or styleUrls point to stylesheet files. The compiler requires one template, rejects styleUrl with styleUrls, and inlines files at build time.

open as a page

For an Angular component created from code, why use ComponentRef.setInput or inputBinding instead of assigning ref.instance fields, and how do outputBinding and twoWayBinding fit in?

level: middleimportance: should knowfreq 40%

basics

~20 s

Assigning ref.instance fields skips ngOnChanges and OnPush dirty marking and cannot set signal inputs. setInput sets an input by public name and marks the view dirty; inputBinding, outputBinding and twoWayBinding declare reactive template-like bindings at creation.

open as a page

With Angular Elements, how do a component's inputs and outputs map to the custom element's attributes, properties and DOM events?

level: middleimportance: should knowfreq 33%

basics

~20 s

Each input becomes a dash-case attribute (from its alias or name) and an element property; attribute strings pass through the input's transform. Each output is dispatched on the element as a CustomEvent named after it, with the value in event.detail.

open as a page

In Angular, why should a test or host code set a component's input with ComponentRef.setInput instead of assigning the field on componentInstance?

level: middleimportance: should knowfreq 40%

basics

~20 s

ComponentRef.setInput sets an input the way a template binding does: it works for signal inputs, runs transforms, triggers ngOnChanges and marks OnPush views for check. Assigning componentInstance fields does none of that and cannot set a read-only InputSignal.

open as a page

In Angular, what do the booleanAttribute and numberAttribute input transforms do, and why does <app-avatar size="64" disabled> need them?

level: middleimportance: should knowfreq 44%

basics

~20 s

They coerce bound values before the input stores them: booleanAttribute makes a present attribute true unless it is 'false', and numberAttribute parses strings, falling back to NaN. Static attributes pass strings, so size and disabled need them.

open as a page

In Angular, what does injecting DestroyRef offer that implementing ngOnDestroy does not, and what decides when its callbacks run?

level: middleimportance: should knowfreq 52%

basics

~20 s

ngOnDestroy is one class method. DestroyRef is an injectable handle whose onDestroy() registers any number of callbacks next to their setup, even inside helper functions, and returns an unregister function; in a component it fires on that component's destruction, elsewhere on its injector's.

open as a page

Which selector forms can an Angular @Component selector use, and when would you pick an attribute selector such as button[app-primary]?

level: middleimportance: should knowfreq 46%

basics

~20 s

An Angular component selector may be an element name, an attribute with an optional exact value, a class, a combination, a comma list or :not(), never a combinator. An attribute selector like button[app-primary] keeps the native button's behaviour.

open as a page

In Angular, when does the implicit <name>Change output of a model() input emit, and when does it stay silent?

level: middleimportance: should knowfreq 40%

basics

~20 s

The Change output emits only when the child writes the model with set() or update() and the new value differs by the signal's equality check; a value the parent pushes in through the binding updates the signal without emitting.

open as a page

In Angular, how does the OutputEmitterRef returned by output() differ from an EventEmitter used with @Output, and what should you check when migrating?

level: middleimportance: should knowfreq 45%

basics

~20 s

EventEmitter is an RxJS Subject with pipe, error and complete, optionally asynchronous. OutputEmitterRef only offers emit and subscribe, is always synchronous, drops its listeners when the component is destroyed, and needs no RxJS. Parent bindings are identical.

open as a page

In Angular, why can a card footer wrapped in <ng-container> or a multi-node @if block miss its select slot, and how does ngProjectAs fix it?

level: middleimportance: should knowfreq 38%

basics

~20 s

Slots match the host's direct children, so a wrapper that does not match the selector goes to the catch-all. Put ngProjectAs="[card-footer]" on the wrapper so it is matched as if it had that selector; the value must be static.

open as a page

In Angular queries, what does the read option change, and what do you get from viewChild('ref') without it?

level: middleimportance: should knowfreq 42%

basics

~20 s

The locator decides which node matches; read decides what value is returned from that node's injector. Without read, a string locator gives the component or exportAs directive it names, else an ElementRef or, on ng-template, a TemplateRef.

open as a page

In an Angular component's styles, what do :host and :host-context() select, and how does Emulated mode compile them?

level: middleimportance: should knowfreq 44%

basics

~20 s

:host targets the component's host element, with :host(.x) adding a condition on it; :host-context(.x) applies when the host or any ancestor matches. In Emulated mode the compiler rewrites both into selectors on the _nghost attribute.

open as a page

An Angular dashboard must render widgets described by a JSON layout from the server; how do you design the dynamic creation, updates and teardown?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Map each JSON type to a component class through an explicit registry with lazy imports, create widgets in a ViewContainerRef with inputBinding/outputBinding, clear the container on relayout, guard against stale async loads, and validate input names with reflectComponentType.

open as a page

Why does an Angular component throw NG0950 when a field initializer reads its input.required() signal, and how would you restructure it?

level: seniorimportance: should knowfreq 42%

basics

~20 s

Field initializers run in the constructor, before Angular sets any input, so reading an unset required input throws NG0950. Derive the value with computed(), read it in the template, or move one-time setup to ngOnInit.

open as a page

showing 1–30 of 44