Skip to main content
The @angular/cdk/coercion package provides utilities for coercing values to specific types, commonly used for component inputs.

Installation

npm install @angular/cdk
import {
  coerceBooleanProperty,
  coerceNumberProperty,
  coerceArray,
  coerceCssPixelValue,
  coerceElement
} from '@angular/cdk/coercion';

Boolean Coercion

Coerce any value to boolean (useful for attribute inputs):
import {Component, Input} from '@angular/core';
import {coerceBooleanProperty} from '@angular/cdk/coercion';

@Component({
  selector: 'app-toggle',
  template: `<div [class.disabled]="disabled">Toggle</div>`,
})
export class ToggleComponent {
  private _disabled = false;

  @Input()
  get disabled(): boolean {
    return this._disabled;
  }
  set disabled(value: any) {
    this._disabled = coerceBooleanProperty(value);
  }
}
Modern approach with transform:
import {Component, Input, booleanAttribute} from '@angular/core';

@Component({
  selector: 'app-toggle',
  template: `<div [class.disabled]="disabled">Toggle</div>`,
})
export class ToggleComponent {
  @Input({transform: booleanAttribute}) disabled = false;
}
Coercion rules:
  • false, "false", null, undefined, ""false
  • Everything else → true
coerceBooleanProperty(true);      // true
coerceBooleanProperty(false);     // false
coerceBooleanProperty('');        // true (empty string)
coerceBooleanProperty('false');   // false
coerceBooleanProperty(null);      // false
coerceBooleanProperty(undefined); // false
coerceBooleanProperty(0);         // true
coerceBooleanProperty('any');     // true

Number Coercion

Coerce values to numbers:
import {Component, Input} from '@angular/core';
import {coerceNumberProperty} from '@angular/cdk/coercion';

@Component({
  selector: 'app-counter',
  template: `<div>Count: {{ count }}</div>`,
})
export class CounterComponent {
  private _count = 0;

  @Input()
  get count(): number {
    return this._count;
  }
  set count(value: any) {
    this._count = coerceNumberProperty(value);
  }
}
Modern approach:
import {Component, Input, numberAttribute} from '@angular/core';

@Component({
  selector: 'app-counter',
  template: `<div>Count: {{ count }}</div>`,
})
export class CounterComponent {
  @Input({transform: numberAttribute}) count = 0;
}
Coercion rules:
coerceNumberProperty('42');       // 42
coerceNumberProperty(42);         // 42
coerceNumberProperty('42.5');     // 42.5
coerceNumberProperty('');         // 0
coerceNumberProperty(null);       // 0
coerceNumberProperty('invalid');  // 0
coerceNumberProperty('5', 10);    // 5 (with fallback 10)
coerceNumberProperty('', 10);     // 10 (fallback used)

Array Coercion

Ensure a value is an array:
import {Component, Input} from '@angular/core';
import {coerceArray} from '@angular/cdk/coercion';

@Component({
  selector: 'app-list',
  template: `
    <ul>
      <li *ngFor="let item of items">{{ item }}</li>
    </ul>
  `,
})
export class ListComponent {
  private _items: string[] = [];

  @Input()
  get items(): string[] {
    return this._items;
  }
  set items(value: string | string[]) {
    this._items = coerceArray(value);
  }
}
Usage:
<!-- Single value becomes array -->
<app-list [items]="'single'"></app-list>
<!-- ['single'] -->

<!-- Array stays array -->
<app-list [items]="['a', 'b', 'c']"></app-list>
<!-- ['a', 'b', 'c'] -->

<!-- Null/undefined becomes empty array -->
<app-list [items]="null"></app-list>
<!-- [] -->

CSS Pixel Value Coercion

Coerce to CSS pixel value:
import {Component, Input} from '@angular/core';
import {coerceCssPixelValue} from '@angular/cdk/coercion';

@Component({
  selector: 'app-box',
  template: `<div [style.width]="width" [style.height]="height">Box</div>`,
})
export class BoxComponent {
  private _width: string;
  private _height: string;

  @Input()
  get width(): string {
    return this._width;
  }
  set width(value: any) {
    this._width = coerceCssPixelValue(value);
  }

  @Input()
  get height(): string {
    return this._height;
  }
  set height(value: any) {
    this._height = coerceCssPixelValue(value);
  }
}
Coercion rules:
coerceCssPixelValue(100);        // '100px'
coerceCssPixelValue('100');      // '100px'
coerceCssPixelValue('100px');    // '100px'
coerceCssPixelValue('50%');      // '50%'
coerceCssPixelValue('auto');     // 'auto'
coerceCssPixelValue(null);       // null

Element Coercion

Coerce ElementRef to HTMLElement:
import {Component, ElementRef} from '@angular/core';
import {coerceElement} from '@angular/cdk/coercion';

@Component({
  selector: 'app-element-wrapper',
  template: `<div #wrapper>Content</div>`,
})
export class ElementWrapperComponent {
  @ViewChild('wrapper') wrapper: ElementRef;

  getElement(): HTMLElement {
    // Works with both ElementRef and HTMLElement
    return coerceElement(this.wrapper);
  }
}
Usage:
const elementRef = new ElementRef(document.body);
coerceElement(elementRef);          // HTMLElement (document.body)
coerceElement(document.body);       // HTMLElement (document.body)

Practical Examples

Flexible Size Input

import {Component, Input} from '@angular/core';
import {coerceNumberProperty, coerceCssPixelValue} from '@angular/cdk/coercion';

@Component({
  selector: 'app-resizable',
  template: `
    <div 
      class="resizable"
      [style.width]="widthPx"
      [style.height]="heightPx">
      Content
    </div>
  `,
})
export class ResizableComponent {
  private _width: number;
  private _height: number;

  @Input()
  get width(): number {
    return this._width;
  }
  set width(value: any) {
    this._width = coerceNumberProperty(value, 200);
  }

  @Input()
  get height(): number {
    return this._height;
  }
  set height(value: any) {
    this._height = coerceNumberProperty(value, 200);
  }

  get widthPx(): string {
    return coerceCssPixelValue(this._width);
  }

  get heightPx(): string {
    return coerceCssPixelValue(this._height);
  }
}
Usage:
<!-- All of these work -->
<app-resizable [width]="300" [height]="400"></app-resizable>
<app-resizable width="300" height="400"></app-resizable>
<app-resizable width="300px" height="400px"></app-resizable>

Multi-value Input

import {Component, Input} from '@angular/core';
import {coerceArray} from '@angular/cdk/coercion';

@Component({
  selector: 'app-tag-list',
  template: `
    <div class="tags">
      <span *ngFor="let tag of tags" class="tag">{{ tag }}</span>
    </div>
  `,
})
export class TagListComponent {
  private _tags: string[] = [];

  @Input()
  get tags(): string[] {
    return this._tags;
  }
  set tags(value: string | string[]) {
    this._tags = coerceArray(value);
  }
}
Usage:
<!-- Single tag -->
<app-tag-list [tags]="'important'"></app-tag-list>

<!-- Multiple tags -->
<app-tag-list [tags]="['important', 'urgent', 'review']"></app-tag-list>

API Reference

coerceBooleanProperty

function coerceBooleanProperty(value: any): boolean
Coerces a data-bound value (typically a string) to a boolean.

coerceNumberProperty

function coerceNumberProperty(value: any, fallbackValue?: number): number
Coerces a data-bound value to a number.

coerceArray

function coerceArray<T>(value: T | readonly T[]): readonly T[]
Wraps value in an array if it isn’t one.

coerceCssPixelValue

function coerceCssPixelValue(value: any): string | null
Coerces a value to a CSS pixel value (adds ‘px’ suffix to numbers).

coerceElement

function coerceElement<T>(elementOrRef: ElementRef<T> | T): T
Coerces an ElementRef or Element to the element.

Modern Approach (Angular 16+)

Angular 16+ provides built-in transform functions:
import {Component, Input, booleanAttribute, numberAttribute} from '@angular/core';

@Component({
  selector: 'app-modern-coercion',
  template: `
    <div>Enabled: {{ enabled }}</div>
    <div>Count: {{ count }}</div>
  `,
})
export class ModernCoercion {
  @Input({transform: booleanAttribute}) enabled = false;
  @Input({transform: numberAttribute}) count = 0;
}

Best Practices

  1. Use modern transforms - Prefer booleanAttribute / numberAttribute in Angular 16+
  2. Provide fallback values - For coerceNumberProperty
  3. Type safety - Use TypeScript generics with coerceArray
  4. Null handling - Coercion functions handle null/undefined gracefully
  5. Documentation - Document expected input types in component docs

Common Patterns

Disabled State

@Input({transform: booleanAttribute}) disabled = false;

Size Properties

@Input({transform: numberAttribute}) size = 100;

Optional Arrays

@Input()
set selectedIds(value: number | number[] | null) {
  this._selectedIds = value ? coerceArray(value) : [];
}

See Also

Build docs developers (and LLMs) love