The Angular CDK Overlay module provides a powerful system for creating positioned floating content like tooltips, dropdowns, modals, and popups. It handles positioning, z-index management, scroll behavior, and backdrop interactions.
The main service for creating and managing overlays.
/**
* Service for creating overlays
*/
class Overlay {
/**
* Create a new overlay with the given configuration
* @param config - Overlay configuration options
* @returns OverlayRef for managing the overlay
*/
create(config?: OverlayConfig): OverlayRef;
/**
* Get the overlay position builder
* @returns OverlayPositionBuilder for creating position strategies
*/
position(): OverlayPositionBuilder;
/**
* Get available scroll strategies
*/
scrollStrategies: ScrollStrategyOptions;
}Usage Example:
import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
constructor(private overlay: Overlay) {}
openTooltip() {
const overlayRef = this.overlay.create({
positionStrategy: this.overlay.position()
.flexibleConnectedTo(this.triggerElement)
.withPositions([{
originX: 'center',
originY: 'bottom',
overlayX: 'center',
overlayY: 'top'
}]),
hasBackdrop: false,
scrollStrategy: this.overlay.scrollStrategies.reposition()
});
const portal = new ComponentPortal(TooltipComponent);
overlayRef.attach(portal);
}Reference to a created overlay for managing its lifecycle and content.
/**
* Reference to a created overlay
*/
class OverlayRef {
/**
* Attach content to the overlay
* @param portal - Portal containing the content to attach
* @returns Reference to the attached content
*/
attach<T>(portal: Portal<T>): ComponentRef<T> | EmbeddedViewRef<T> | null;
/**
* Detach content from the overlay
* @returns The detached content
*/
detach(): any;
/**
* Dispose of the overlay and clean up resources
*/
dispose(): void;
/**
* Whether the overlay has attached content
* @returns True if content is attached
*/
hasAttached(): boolean;
/**
* Observable for backdrop click events
* @returns Observable that emits when backdrop is clicked
*/
backdropClick(): Observable<MouseEvent>;
/**
* Observable for attachment events
* @returns Observable that emits when content is attached
*/
attachments(): Observable<void>;
/**
* Observable for detachment events
* @returns Observable that emits when content is detached
*/
detachments(): Observable<void>;
/**
* Observable for keydown events on the overlay
* @returns Observable that emits keydown events
*/
keydownEvents(): Observable<KeyboardEvent>;
/**
* Observable for pointer events outside the overlay
* @returns Observable that emits outside pointer events
*/
outsidePointerEvents(): Observable<MouseEvent>;
/**
* Get the overlay configuration
* @returns Current overlay configuration
*/
getConfig(): OverlayConfig;
/**
* Update the overlay position
*/
updatePosition(): void;
/**
* Update the position strategy
* @param strategy - New position strategy
*/
updatePositionStrategy(strategy: PositionStrategy): void;
/**
* Update the overlay size
* @param config - New size configuration
*/
updateSize(config: OverlaySizeConfig): void;
}Configuration options for creating overlays.
/**
* Configuration for creating an overlay
*/
class OverlayConfig {
/** Position strategy for the overlay */
positionStrategy?: PositionStrategy;
/** Scroll strategy for the overlay */
scrollStrategy?: ScrollStrategy;
/** CSS classes to add to the overlay panel */
panelClass?: string | string[];
/** Whether the overlay has a backdrop */
hasBackdrop?: boolean;
/** CSS classes to add to the backdrop */
backdropClass?: string | string[];
/** Width of the overlay */
width?: number | string;
/** Height of the overlay */
height?: number | string;
/** Minimum width of the overlay */
minWidth?: number | string;
/** Minimum height of the overlay */
minHeight?: number | string;
/** Maximum width of the overlay */
maxWidth?: number | string;
/** Maximum height of the overlay */
maxHeight?: number | string;
/** Text direction for the overlay */
direction?: Direction | Directionality;
/** Whether to dispose overlay on navigation */
disposeOnNavigation?: boolean;
}
/**
* Configuration for updating overlay size
*/
interface OverlaySizeConfig {
width?: number | string;
height?: number | string;
minWidth?: number | string;
minHeight?: number | string;
maxWidth?: number | string;
maxHeight?: number | string;
}Different strategies for positioning overlays relative to trigger elements or globally.
/**
* Builder for creating position strategies
*/
class OverlayPositionBuilder {
/**
* Create a global position strategy
* @returns GlobalPositionStrategy for absolute positioning
*/
global(): GlobalPositionStrategy;
/**
* Create a connected position strategy
* @param origin - Element or point to connect to
* @returns FlexibleConnectedPositionStrategy for relative positioning
*/
connectedTo(
origin: ElementRef | Element | Point & {width?: number; height?: number;}
): FlexibleConnectedPositionStrategy;
}
/**
* Base class for position strategies
*/
abstract class PositionStrategy {
/** Attach the strategy to an overlay reference */
attach(overlayRef: OverlayRef): void;
/** Apply the positioning */
apply(): void;
/** Detach the strategy */
detach(): void;
/** Dispose of the strategy */
dispose(): void;
}
/**
* Global positioning strategy for absolute positioning
*/
class GlobalPositionStrategy extends PositionStrategy {
/** Set top position */
top(value?: string): this;
/** Set left position */
left(value?: string): this;
/** Set bottom position */
bottom(value?: string): this;
/** Set right position */
right(value?: string): this;
/** Set width */
width(value?: string): this;
/** Set height */
height(value?: string): this;
/** Center horizontally */
centerHorizontally(offset?: string): this;
/** Center vertically */
centerVertically(offset?: string): this;
}
/**
* Flexible connected positioning strategy for relative positioning
*/
class FlexibleConnectedPositionStrategy extends PositionStrategy {
/**
* Set the positions to try
* @param positions - Array of position configurations
*/
withPositions(positions: ConnectedPosition[]): this;
/**
* Whether to allow flexible dimensions
* @param flexibleDimensions - Allow flexible sizing
*/
withFlexibleDimensions(flexibleDimensions?: boolean): this;
/**
* Whether to push overlay on-screen if it would overflow
* @param canPush - Allow pushing overlay
*/
withPush(canPush?: boolean): this;
/**
* Whether to grow overlay after opening
* @param growAfterOpen - Allow growing after open
*/
withGrowAfterOpen(growAfterOpen?: boolean): this;
/**
* Set viewport margin
* @param margin - Margin from viewport edge
*/
withViewportMargin(margin: number): this;
/**
* Whether to lock position after opening
* @param isLocked - Lock position
*/
withLockedPosition(isLocked?: boolean): this;
/**
* Set the origin element
* @param origin - New origin element or point
*/
withOrigin(
origin: ElementRef | Element | Point & {width?: number; height?: number;}
): this;
/**
* Set default X offset
* @param offset - Default X offset
*/
withDefaultOffsetX(offset: number): this;
/**
* Set default Y offset
* @param offset - Default Y offset
*/
withDefaultOffsetY(offset: number): this;
}
/**
* Connected position configuration
*/
interface ConnectedPosition {
/** Horizontal origin point */
originX: 'start' | 'center' | 'end';
/** Vertical origin point */
originY: 'top' | 'center' | 'bottom';
/** Horizontal overlay point */
overlayX: 'start' | 'center' | 'end';
/** Vertical overlay point */
overlayY: 'top' | 'center' | 'bottom';
/** Position weight for fallback ordering */
weight?: number;
/** X offset from origin */
offsetX?: number;
/** Y offset from origin */
offsetY?: number;
/** CSS classes for this position */
panelClass?: string | string[];
}Strategies for handling scroll behavior when overlays are open.
/**
* Available scroll strategies
*/
interface ScrollStrategyOptions {
/** No-op scroll strategy (does nothing) */
noop(): NoopScrollStrategy;
/** Close overlay when scrolling */
close(config?: CloseScrollStrategyConfig): CloseScrollStrategy;
/** Block scrolling while overlay is open */
block(): BlockScrollStrategy;
/** Reposition overlay when scrolling */
reposition(config?: RepositionScrollStrategyConfig): RepositionScrollStrategy;
}
/**
* Base scroll strategy interface
*/
interface ScrollStrategy {
/** Attach strategy to overlay reference */
attach(overlayRef: OverlayRef): void;
/** Enable the scroll strategy */
enable(): void;
/** Disable the scroll strategy */
disable(): void;
/** Detach the strategy */
detach(): void;
}
/**
* Configuration for close scroll strategy
*/
interface CloseScrollStrategyConfig {
/** Threshold for closing */
threshold?: number;
}
/**
* Configuration for reposition scroll strategy
*/
interface RepositionScrollStrategyConfig {
/** Scroll throttle in milliseconds */
scrollThrottle?: number;
/** Whether to auto-close on scroll */
autoClose?: boolean;
}Directive for creating connected overlays declaratively.
/**
* Directive for creating connected overlays
*/
@Directive({
selector: '[cdk-connected-overlay], [connected-overlay], [cdkConnectedOverlay]'
})
class CdkConnectedOverlay implements OnDestroy {
/** Origin element for positioning */
@Input() cdkConnectedOverlayOrigin: CdkOverlayOrigin;
/** Position configurations */
@Input() cdkConnectedOverlayPositions: ConnectedPosition[];
/** X offset */
@Input() cdkConnectedOverlayOffsetX: number;
/** Y offset */
@Input() cdkConnectedOverlayOffsetY: number;
/** Overlay width */
@Input() cdkConnectedOverlayWidth: number | string;
/** Overlay height */
@Input() cdkConnectedOverlayHeight: number | string;
/** Minimum width */
@Input() cdkConnectedOverlayMinWidth: number | string;
/** Minimum height */
@Input() cdkConnectedOverlayMinHeight: number | string;
/** Backdrop CSS classes */
@Input() cdkConnectedOverlayBackdropClass: string | string[];
/** Panel CSS classes */
@Input() cdkConnectedOverlayPanelClass: string | string[];
/** Whether overlay is open */
@Input() cdkConnectedOverlayOpen: boolean;
/** Whether to disable close on backdrop click */
@Input() cdkConnectedOverlayDisableClose: boolean;
/** Scroll strategy */
@Input() cdkConnectedOverlayScrollStrategy: ScrollStrategy;
/** Whether to show backdrop */
@Input() cdkConnectedOverlayHasBackdrop: boolean;
/** Whether to lock position */
@Input() cdkConnectedOverlayLockPosition: boolean;
/** Whether to allow flexible dimensions */
@Input() cdkConnectedOverlayFlexibleDimensions: boolean;
/** Whether to grow after opening */
@Input() cdkConnectedOverlayGrowAfterOpen: boolean;
/** Whether to push overlay on-screen */
@Input() cdkConnectedOverlayPush: boolean;
/** Backdrop click events */
@Output() backdropClick: EventEmitter<MouseEvent>;
/** Position change events */
@Output() positionChange: EventEmitter<ConnectedOverlayPositionChange>;
/** Attach events */
@Output() attach: EventEmitter<void>;
/** Detach events */
@Output() detach: EventEmitter<void>;
/** Overlay keydown events */
@Output() overlayKeydown: EventEmitter<KeyboardEvent>;
/** Outside click events */
@Output() overlayOutsideClick: EventEmitter<MouseEvent>;
}
/**
* Directive for marking overlay origin elements
*/
@Directive({
selector: '[cdk-overlay-origin], [overlay-origin], [cdkOverlayOrigin]'
})
class CdkOverlayOrigin {
/** The element reference */
elementRef: ElementRef;
}Service for managing the container element that holds all overlays.
/**
* Service for managing the overlay container
*/
class OverlayContainer {
/**
* Get the container element for overlays
* @returns HTMLElement that contains all overlays
*/
getContainerElement(): HTMLElement;
}/**
* Point interface for positioning
*/
interface Point {
x: number;
y: number;
}
/**
* Position change event for connected overlays
*/
interface ConnectedOverlayPositionChange {
/** The position that was applied */
connectionPair: ConnectedPosition;
/** The scroll position */
scrollableViewProperties: ScrollingVisibility;
}
/**
* Scrolling visibility information
*/
interface ScrollingVisibility {
isOriginClipped: boolean;
isOriginOutsideView: boolean;
isOverlayClipped: boolean;
isOverlayOutsideView: boolean;
}import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
@Component({
selector: 'app-tooltip-trigger',
template: '<button (mouseenter)="showTooltip()" (mouseleave)="hideTooltip()">Hover me</button>'
})
export class TooltipTriggerComponent {
private overlayRef: OverlayRef | null = null;
constructor(private overlay: Overlay) {}
showTooltip() {
if (this.overlayRef) return;
const positionStrategy = this.overlay.position()
.flexibleConnectedTo(this.elementRef)
.withPositions([
{
originX: 'center',
originY: 'bottom',
overlayX: 'center',
overlayY: 'top',
offsetY: 8
}
]);
this.overlayRef = this.overlay.create({
positionStrategy,
scrollStrategy: this.overlay.scrollStrategies.reposition(),
hasBackdrop: false
});
const portal = new ComponentPortal(TooltipComponent);
this.overlayRef.attach(portal);
}
hideTooltip() {
if (this.overlayRef) {
this.overlayRef.dispose();
this.overlayRef = null;
}
}
}import { Overlay, OverlayRef } from '@angular/cdk/overlay';
import { ComponentPortal } from '@angular/cdk/portal';
@Injectable()
export class DialogService {
constructor(private overlay: Overlay) {}
open<T>(component: ComponentType<T>, data?: any): OverlayRef {
const overlayRef = this.overlay.create({
hasBackdrop: true,
backdropClass: 'dialog-backdrop',
panelClass: 'dialog-panel',
positionStrategy: this.overlay.position()
.global()
.centerHorizontally()
.centerVertically(),
scrollStrategy: this.overlay.scrollStrategies.block()
});
const portal = new ComponentPortal(component);
const componentRef = overlayRef.attach(portal);
// Pass data to component
if (data) {
Object.assign(componentRef.instance, data);
}
// Close on backdrop click
overlayRef.backdropClick().subscribe(() => {
overlayRef.dispose();
});
return overlayRef;
}
}