cdkTrapFocus from @angular/cdk/a11y confines keyboard focus to its host element while active — Tab and Shift+Tab cycle through focusable descendants but never leave the trap. It's the standard way to make a modal dialog accessible. Pair it with autofocus (or any initial-focus directive) on the first input so screen-reader users land in the right place.
<button (click)="isOpen.set(true)" [color]="colors.primary">Open dialog</button>
<!-- The modal traps focus itself, and returns it to the button on close. -->
<bs-modal [(open)]="isOpen">
<span *bsModalHeader>Edit details</span>
<input type="text" aria-label="First field" placeholder="Focus starts in the dialog">
<input type="text" aria-label="Second field" placeholder="Tab stays inside the dialog">
<ng-container *bsModalFooter>
<button type="button" data-bs-dismiss="modal" [color]="colors.secondary">Close</button>
</ng-container>
</bs-modal>
import { Component, signal } from '@angular/core';
import { Color } from '@mintplayer/ng-bootstrap';
import { BsButtonTypeDirective } from '@mintplayer/ng-bootstrap/button-type';
import { BsModalComponent, BsModalFooterDirective, BsModalHeaderDirective } from '@mintplayer/ng-bootstrap/modal';
@Component({
selector: 'my-focus-trap-demo',
templateUrl: './my-focus-trap-demo.component.html',
imports: [BsButtonTypeDirective, BsModalComponent, BsModalHeaderDirective, BsModalFooterDirective],
})
export class MyFocusTrapDemoComponent {
protected readonly colors = Color;
protected readonly isOpen = signal(false);
}