The Angular CDK provides several utility modules for platform detection, type coercion, key codes, clipboard operations, and other common tasks needed when building components.
Service for detecting the current platform, browser, and environment capabilities.
/**
* Service for platform and browser detection
*/
class Platform {
/** Whether the code is running in a browser environment */
isBrowser: boolean;
/** Whether the browser is Microsoft Edge */
EDGE: boolean;
/** Whether the browser uses the Trident rendering engine (Internet Explorer) */
TRIDENT: boolean;
/** Whether the browser uses the Blink rendering engine (Chrome, Edge, Opera) */
BLINK: boolean;
/** Whether the browser uses the WebKit rendering engine (Safari, older Chrome) */
WEBKIT: boolean;
/** Whether the platform is iOS */
IOS: boolean;
/** Whether the browser is Firefox */
FIREFOX: boolean;
/** Whether the platform is Android */
ANDROID: boolean;
/** Whether the browser is Safari */
SAFARI: boolean;
}Usage Example:
import { Platform } from '@angular/cdk/platform';
constructor(private platform: Platform) {
if (this.platform.isBrowser) {
// Browser-specific code
if (this.platform.IOS) {
// iOS-specific behavior
}
if (this.platform.ANDROID) {
// Android-specific behavior
}
}
}Functions for detecting browser feature support.
/**
* Check if passive event listeners are supported
* @returns True if passive event listeners are supported
*/
function supportsPassiveEventListeners(): boolean;
/**
* Check if CSS scroll-behavior is supported
* @returns True if scroll-behavior is supported
*/
function supportsScrollBehavior(): boolean;
/**
* Get the level of Shadow DOM support
* @returns Shadow DOM support level
*/
function getShadowDomSupportLevel(): ShadowDomVersion;
/**
* Get the RTL scroll axis type for the current browser
* @returns RTL scroll axis type
*/
function getRtlScrollAxisType(): RtlScrollAxisType;
/**
* Normalize passive listener options based on browser support
* @param options - Listener options
* @returns Normalized options
*/
function normalizePassiveListenerOptions(options: AddEventListenerOptions): AddEventListenerOptions | boolean;
/**
* Shadow DOM support levels
*/
const enum ShadowDomVersion {
NONE,
V0,
V1
}
/**
* RTL scroll axis types
*/
const enum RtlScrollAxisType {
NORMAL,
NEGATED,
INVERTED
}Functions for safely coercing values to specific types.
/**
* Coerce a value to a boolean
* @param value - Value to coerce
* @returns Boolean representation of the value
*/
function coerceBooleanProperty(value: any): boolean;
/**
* Coerce a value to a number
* @param value - Value to coerce
* @param fallback - Fallback value if coercion fails
* @returns Number representation of the value or fallback
*/
function coerceNumberProperty(value: any, fallback?: number): number;
/**
* Coerce a value to an array
* @param value - Value to coerce
* @returns Array containing the value or the value if already an array
*/
function coerceArray<T>(value: T | T[]): T[];
/**
* Coerce a value to a CSS pixel value string
* @param value - Value to coerce
* @returns CSS pixel value string
*/
function coerceCssPixelValue(value: any): string;
/**
* Coerce an ElementRef or Element to Element
* @param elementOrRef - ElementRef or Element
* @returns The underlying Element
*/
function coerceElement<T>(elementOrRef: ElementRef<T> | T): T;
/**
* Coerce a string or string array to string array
* @param value - Value to coerce
* @returns String array
*/
function coerceStringArray(value: string | string[]): string[];
/**
* Input types that can be coerced to boolean
*/
type BooleanInput = string | boolean | null | undefined;
/**
* Input types that can be coerced to number
*/
type NumberInput = string | number | null | undefined;Usage Example:
import { coerceBooleanProperty, coerceNumberProperty } from '@angular/cdk/coercion';
@Component({
selector: 'app-example'
})
export class ExampleComponent {
private _disabled = false;
private _size = 0;
@Input()
get disabled(): boolean {
return this._disabled;
}
set disabled(value: BooleanInput) {
this._disabled = coerceBooleanProperty(value);
}
@Input()
get size(): number {
return this._size;
}
set size(value: NumberInput) {
this._size = coerceNumberProperty(value, 10);
}
}Constants for keyboard key codes and modifier key detection.
// Navigation keys
const TAB = 9;
const ENTER = 13;
const ESCAPE = 27;
const SPACE = 32;
const PAGE_UP = 33;
const PAGE_DOWN = 34;
const END = 35;
const HOME = 36;
const LEFT_ARROW = 37;
const UP_ARROW = 38;
const RIGHT_ARROW = 39;
const DOWN_ARROW = 40;
// Edit keys
const BACKSPACE = 8;
const DELETE = 46;
// Letter keys
const A = 65;
const B = 66;
// ... continues through Z = 90
// Number keys
const ZERO = 48;
const ONE = 49;
// ... continues through NINE = 57
// Function keys
const F1 = 112;
const F2 = 113;
// ... continues through F12 = 123
// Punctuation keys
const COMMA = 188;
const SEMICOLON = 186;
const EQUALS = 187;
const DASH = 189;
const PERIOD = 190;
const SLASH = 191;
/**
* Check if a keyboard event has modifier keys pressed
* @param event - Keyboard event
* @param modifiers - Modifier keys to check for
* @returns True if any of the specified modifiers are pressed
*/
function hasModifierKey(event: KeyboardEvent, ...modifiers: ModifierKey[]): boolean;
/**
* Modifier key types
*/
type ModifierKey = 'altKey' | 'shiftKey' | 'ctrlKey' | 'metaKey';Usage Example:
import { ENTER, SPACE, hasModifierKey } from '@angular/cdk/keycodes';
@HostListener('keydown', ['$event'])
onKeyDown(event: KeyboardEvent) {
switch (event.keyCode) {
case ENTER:
case SPACE:
if (!hasModifierKey(event, 'altKey', 'shiftKey')) {
this.activate();
event.preventDefault();
}
break;
}
}Service for clipboard operations with fallback support.
/**
* Service for clipboard operations
*/
class Clipboard {
/**
* Copy text to the clipboard
* @param text - Text to copy
* @returns True if copy was successful
*/
copy(text: string): boolean;
/**
* Begin a copy operation (for advanced use cases)
* @param text - Text to copy
* @returns PendingCopy instance for managing the operation
*/
beginCopy(text: string): PendingCopy;
}
/**
* Class for managing pending copy operations
*/
class PendingCopy {
/**
* Execute the copy operation
* @returns True if copy was successful
*/
copy(): boolean;
/**
* Clean up resources
*/
destroy(): void;
}
/**
* Directive for copying text to clipboard
*/
@Directive({
selector: '[cdkCopyToClipboard]'
})
class CdkCopyToClipboard {
/** Text to copy to clipboard */
@Input('cdkCopyToClipboard') text: string;
/** Number of copy attempts before giving up */
@Input('cdkCopyToClipboardAttempts') attempts: number = 1;
/** Event emitted after copy attempt */
@Output('cdkCopyToClipboardCopied') copied: EventEmitter<boolean> = new EventEmitter<boolean>();
}Usage Example:
import { Clipboard } from '@angular/cdk/clipboard';
constructor(private clipboard: Clipboard) {}
copyToClipboard(text: string) {
const successful = this.clipboard.copy(text);
if (successful) {
console.log('Text copied to clipboard');
}
}Service and directive for handling text direction (LTR/RTL).
/**
* Service for detecting and managing text direction
*/
class Directionality implements OnDestroy {
/** Current text direction */
value: Direction;
/** Observable that emits when direction changes */
change: Observable<Direction>;
ngOnDestroy(): void;
}
/**
* Text direction values
*/
type Direction = 'ltr' | 'rtl';
/**
* Directive for setting text direction
*/
@Directive({
selector: '[dir]'
})
class Dir {
/** Text direction */
@Input() dir: Direction;
/** Event emitted when direction changes */
@Output() dirChange: EventEmitter<Direction>;
}
/**
* Injection token for document reference
*/
const DIR_DOCUMENT: InjectionToken<Document>;Service for responsive breakpoint observation.
/**
* Service for observing viewport breakpoints
*/
class BreakpointObserver implements OnDestroy {
/**
* Observe breakpoint changes
* @param value - Breakpoint query or queries to observe
* @returns Observable that emits breakpoint state changes
*/
observe(value: string | string[]): Observable<BreakpointState>;
/**
* Check if breakpoint currently matches
* @param value - Breakpoint query or queries to check
* @returns True if breakpoint matches
*/
isMatched(value: string | string[]): boolean;
ngOnDestroy(): void;
}
/**
* Result of breakpoint observation
*/
interface BreakpointState {
/** Whether the breakpoint matches */
matches: boolean;
/** Map of individual breakpoint query results */
breakpoints: {
[key: string]: boolean;
};
}
/**
* Service for media query matching
*/
class MediaMatcher {
/**
* Create a MediaQueryList for the given query
* @param query - CSS media query
* @returns MediaQueryList instance
*/
matchMedia(query: string): MediaQueryList;
}
/**
* Predefined breakpoint constants
*/
const Breakpoints = {
XSmall: '(max-width: 599.98px)',
Small: '(min-width: 600px) and (max-width: 959.98px)',
Medium: '(min-width: 960px) and (max-width: 1279.98px)',
Large: '(min-width: 1280px) and (max-width: 1919.98px)',
XLarge: '(min-width: 1920px)',
Handset: '(max-width: 599.98px) and (orientation: portrait), (max-width: 959.98px) and (orientation: landscape)',
Tablet: '(min-width: 600px) and (max-width: 839.98px) and (orientation: portrait), (min-width: 960px) and (max-width: 1279.98px) and (orientation: landscape)',
Web: '(min-width: 840px) and (orientation: portrait), (min-width: 1280px) and (orientation: landscape)',
HandsetPortrait: '(max-width: 599.98px) and (orientation: portrait)',
TabletPortrait: '(min-width: 600px) and (max-width: 839.98px) and (orientation: portrait)',
WebPortrait: '(min-width: 840px) and (orientation: portrait)',
HandsetLandscape: '(max-width: 959.98px) and (orientation: landscape)',
TabletLandscape: '(min-width: 960px) and (max-width: 1279.98px) and (orientation: landscape)',
WebLandscape: '(min-width: 1280px) and (orientation: landscape)'
};Usage Example:
import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
constructor(private breakpointObserver: BreakpointObserver) {
this.isHandset$ = this.breakpointObserver.observe(Breakpoints.Handset)
.pipe(
map(result => result.matches)
);
}/**
* Module for platform detection functionality
*/
@NgModule({})
class PlatformModule {}
/**
* Module for clipboard functionality
*/
@NgModule({
declarations: [CdkCopyToClipboard],
exports: [CdkCopyToClipboard]
})
class ClipboardModule {}
/**
* Module for bidirectional text support
*/
@NgModule({
declarations: [Dir],
exports: [Dir]
})
class BidiModule {}
/**
* Module for layout and breakpoint functionality
*/
@NgModule({})
class LayoutModule {}import { BreakpointObserver, Breakpoints } from '@angular/cdk/layout';
import { map } from 'rxjs/operators';
@Component({
selector: 'app-responsive',
template: `
<div [class.mobile]="isHandset$ | async">
Content adapts to screen size
</div>
`
})
export class ResponsiveComponent {
isHandset$ = this.breakpointObserver.observe(Breakpoints.Handset)
.pipe(map(result => result.matches));
constructor(private breakpointObserver: BreakpointObserver) {}
}import { Platform } from '@angular/cdk/platform';
@Injectable()
export class StorageService {
constructor(private platform: Platform) {}
setItem(key: string, value: string): void {
if (this.platform.isBrowser) {
localStorage.setItem(key, value);
}
}
getItem(key: string): string | null {
if (this.platform.isBrowser) {
return localStorage.getItem(key);
}
return null;
}
}import { coerceBooleanProperty, coerceNumberProperty, BooleanInput, NumberInput } from '@angular/cdk/coercion';
@Component({
selector: 'app-configurable'
})
export class ConfigurableComponent {
private _disabled = false;
private _tabIndex = 0;
@Input()
get disabled(): boolean {
return this._disabled;
}
set disabled(value: BooleanInput) {
this._disabled = coerceBooleanProperty(value);
}
@Input()
get tabIndex(): number {
return this._tabIndex;
}
set tabIndex(value: NumberInput) {
this._tabIndex = coerceNumberProperty(value, 0);
}
}