Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions src/cdk/a11y/focus-trap/event-listener-inert-strategy.spec.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,21 @@ describe('EventListenerFocusTrapInertStrategy', () => {
componentInstance.secondFocusableElement.nativeElement,
'Expected second focusable element to be focused');
}));

it('should not intercept focus if it moved outside the trap and back in again',
fakeAsync(() => {
const fixture = createComponent(SimpleFocusTrap, providers);
fixture.detectChanges();
const {secondFocusableElement, outsideFocusableElement} = fixture.componentInstance;

outsideFocusableElement.nativeElement.focus();
secondFocusableElement.nativeElement.focus();
flush();

expect(fixture.componentInstance.activeElement).toBe(secondFocusableElement.nativeElement,
'Expected second focusable element to be focused');
}));

});

function createComponent<T>(componentType: Type<T>, providers: Array<Object> = []
Expand Down Expand Up @@ -91,6 +106,7 @@ class SimpleFocusTrap implements AfterViewInit {
});

this.focusTrap = this._focusTrapFactory.create(this.focusTrapElement.nativeElement);
spyOnProperty(document, 'activeElement', 'get').and.callFake(() => this.activeElement);
this.focusTrap.focusFirstTabbableElementWhenReady();
}
}
8 changes: 5 additions & 3 deletions src/cdk/a11y/focus-trap/event-listener-inert-strategy.ts
Original file line number Diff line number Diff line change
Expand Up @@ -49,15 +49,17 @@ export class EventListenerFocusTrapInertStrategy implements FocusTrapInertStrate
*/
private _trapFocus(focusTrap: ConfigurableFocusTrap, event: FocusEvent) {
const target = event.target as HTMLElement;
const focusTrapRoot = focusTrap._element;

// Don't refocus if target was in an overlay, because the overlay might be associated
// with an element inside the FocusTrap, ex. mat-select.
if (!focusTrap._element.contains(target) &&
closest(target, 'div.cdk-overlay-pane') === null) {
if (!focusTrapRoot.contains(target) && closest(target, 'div.cdk-overlay-pane') === null) {
// Some legacy FocusTrap usages have logic that focuses some element on the page
// just before FocusTrap is destroyed. For backwards compatibility, wait
// to be sure FocusTrap is still enabled before refocusing.
setTimeout(() => {
if (focusTrap.enabled) {
// Check whether focus wasn't put back into the focus trap while the timeout was pending.
if (focusTrap.enabled && !focusTrapRoot.contains(focusTrap._document.activeElement)) {
focusTrap.focusFirstTabbableElement();
}
});
Expand Down