Angular CDK Usage Guidelines
IMPORTANT: Always prefer Angular CDK primitives over custom implementations for common UI patterns.
Angular CDK (Component Dev Kit) provides behavior primitives that are:
- Fully accessible (WCAG compliant)
- Well-tested across browsers
- Properly handling edge cases
When to Use Angular CDK
Dialog/Modal (@angular/cdk/dialog)
Always use CDK Dialog for:
- Modal dialogs
- Command palettes
- Confirmation dialogs
- Any overlay that blocks interaction with the rest of the page
import { Dialog, DialogModule } from '@angular/cdk/dialog';
@Component({
imports: [DialogModule],
})
export class MyComponent {
private dialog = inject(Dialog);
openDialog() {
this.dialog.open(MyDialogComponent, {
width: '500px',
hasBackdrop: true,
backdropClass: 'cdk-overlay-dark-backdrop',
});
}
}
Benefits:
- Automatic focus trapping
- Escape key handling
- Backdrop click handling
- Scroll blocking
- ARIA attributes
- Focus restoration on close
Overlay (@angular/cdk/overlay)
Use CDK Overlay for:
- Dropdowns
- Tooltips
- Popovers
- Context menus
- Any floating UI element
import { Overlay, OverlayModule } from '@angular/cdk/overlay';
@Component({
imports: [OverlayModule],
})
export class DropdownComponent {
private overlay = inject(Overlay);
openDropdown(trigger: ElementRef) {
const positionStrategy = this.overlay
.position()
.flexibleConnectedTo(trigger)
.withPositions([
{
originX: 'start',
originY: 'bottom',
overlayX: 'start',
overlayY: 'top',
},
]);
const overlayRef = this.overlay.create({
positionStrategy,
hasBackdrop: true,
backdropClass: 'cdk-overlay-transparent-backdrop',
});
}
}
Accessibility (@angular/cdk/a11y)
Use CDK A11y for:
- Focus trapping in modals
- Focus monitoring
- Live announcer for screen readers
- Keyboard navigation
import { A11yModule, FocusTrap, LiveAnnouncer } from '@angular/cdk/a11y';
@Component({
imports: [A11yModule],
template: `
<div cdkTrapFocus>
<!-- Focus stays within this container -->
</div>
`,
})
export class ModalComponent {
private liveAnnouncer = inject(LiveAnnouncer);
announce(message: string) {
this.liveAnnouncer.announce(message, 'polite');
}
}
Portal (@angular/cdk/portal)
Use CDK Portal for:
- Rendering content outside the component tree
- Dynamic component insertion
- Template portals
import { ComponentPortal, PortalModule } from '@angular/cdk/portal';
@Component({
imports: [PortalModule],
template: ` <ng-template cdkPortalOutlet></ng-template> `,
})
export class PortalHostComponent {
attachComponent(component: Type<any>) {
const portal = new ComponentPortal(component);
this.portalOutlet.attach(portal);
}
}
Scrolling (@angular/cdk/scrolling)
Use CDK Scrolling for:
- Virtual scrolling (long lists)
- Scroll blocking
- Scroll position restoration
import { ScrollingModule } from '@angular/cdk/scrolling';
@Component({
imports: [ScrollingModule],
template: `
<cdk-virtual-scroll-viewport itemSize="50" class="h-[400px]">
<div *cdkVirtualFor="let item of items">{{ item }}</div>
</cdk-virtual-scroll-viewport>
`,
})
export class VirtualListComponent {
items = Array.from({ length: 10000 }, (_, i) => `Item ${i}`);
}
Drag and Drop (@angular/cdk/drag-drop)
Use CDK Drag and Drop for:
- Sortable lists
- Drag-and-drop interfaces
- Reorderable items
import {
CdkDragDrop,
DragDropModule,
moveItemInArray,
} from '@angular/cdk/drag-drop';
@Component({
imports: [DragDropModule],
template: `
<div cdkDropList (cdkDropListDropped)="drop($event)">
@for (item of items; track item) {
<div cdkDrag>{{ item }}</div>
}
</div>
`,
})
export class SortableListComponent {
items = ['Item 1', 'Item 2', 'Item 3'];
drop(event: CdkDragDrop<string[]>) {
moveItemInArray(this.items, event.previousIndex, event.currentIndex);
}
}
CDK Modules Reference
| Module | Use Case |
|---|---|
@angular/cdk/dialog |
Modal dialogs, command palettes |
@angular/cdk/overlay |
Dropdowns, tooltips, popovers |
@angular/cdk/a11y |
Focus management, screen readers |
@angular/cdk/portal |
Dynamic content rendering |
@angular/cdk/scrolling |
Virtual scrolling, scroll blocking |
@angular/cdk/drag-drop |
Drag and drop, sortable lists |
@angular/cdk/clipboard |
Copy to clipboard |
@angular/cdk/text-field |
Auto-resize textareas |
@angular/cdk/platform |
Platform detection |
@angular/cdk/layout |
Breakpoint observer |
What NOT to Do
// Bad: Custom overlay implementation
@Component({
template: `
@if (isOpen) {
<div class="custom-backdrop" (click)="close()">
<div class="custom-dialog">...</div>
</div>
}
`,
})
export class CustomDialogComponent {
@HostListener('window:keydown.escape')
close() {
/* manual escape handling */
}
}
// Good: Use CDK Dialog
@Component({})
export class DialogTriggerComponent {
private dialog = inject(Dialog);
openDialog() {
this.dialog.open(DialogContentComponent);
}
}
Accessibility Checklist for CDK Components
- Use
cdkTrapFocusfor modals and dialogs - Use
LiveAnnouncerfor dynamic content changes - Use
FocusMonitorfor focus state styling - Use
cdkAriaDescribedByfor additional descriptions - Test with keyboard navigation
- Test with screen readers
Performance Considerations
- Use virtual scrolling for lists > 100 items
- Lazy load overlay content when possible
- Detach overlays when not visible
- Use
OnPushchange detection with CDK components
Converted and distributed by TomeVault — claim your Tome and manage your conversions.