Skip to content

Commit 27347b5

Browse files
crisbetovivian-hu-zz
authored andcommitted
fix(focus-trap): warn if initial element is not focusable (#13960)
Currently if the consumer sets the `cdkFocusInitial` group on a non-focusable element, nothing will happen. These changes add a warning if the app is running in dev mode. Relates to #13953.
1 parent 4be1b06 commit 27347b5

File tree

2 files changed

+30
-0
lines changed

2 files changed

+30
-0
lines changed

src/cdk/a11y/focus-trap/focus-trap.spec.ts

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ describe('FocusTrap', () => {
1616
FocusTrapWithSvg,
1717
FocusTrapWithoutFocusableElements,
1818
FocusTrapWithAutoCapture,
19+
FocusTrapUnfocusableTarget,
1920
],
2021
});
2122

@@ -138,6 +139,18 @@ describe('FocusTrap', () => {
138139
focusTrapInstance.focusLastTabbableElement();
139140
expect(document.activeElement!.id).toBe('last');
140141
});
142+
143+
it('should warn if the initial focus target is not focusable', () => {
144+
const alternateFixture = TestBed.createComponent(FocusTrapUnfocusableTarget);
145+
alternateFixture.detectChanges();
146+
focusTrapInstance = fixture.componentInstance.focusTrapDirective.focusTrap;
147+
148+
spyOn(console, 'warn');
149+
focusTrapInstance.focusInitialElement();
150+
151+
expect(console.warn).toHaveBeenCalled();
152+
});
153+
141154
});
142155

143156
describe('special cases', () => {
@@ -235,6 +248,16 @@ class FocusTrapTargets {
235248
@ViewChild(CdkTrapFocus) focusTrapDirective: CdkTrapFocus;
236249
}
237250

251+
@Component({
252+
template: `
253+
<div cdkTrapFocus>
254+
<div cdkFocusInitial></div>
255+
</div>
256+
`
257+
})
258+
class FocusTrapUnfocusableTarget {
259+
@ViewChild(CdkTrapFocus) focusTrapDirective: CdkTrapFocus;
260+
}
238261

239262
@Component({
240263
template: `

src/cdk/a11y/focus-trap/focus-trap.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ import {
1818
NgZone,
1919
OnDestroy,
2020
DoCheck,
21+
isDevMode,
2122
} from '@angular/core';
2223
import {take} from 'rxjs/operators';
2324
import {InteractivityChecker} from '../interactivity-checker/interactivity-checker';
@@ -189,6 +190,12 @@ export class FocusTrap {
189190
`will be removed in 8.0.0`, redirectToElement);
190191
}
191192

193+
// Warn the consumer if the element they've pointed to
194+
// isn't focusable, when not in production mode.
195+
if (isDevMode() && !this._checker.isFocusable(redirectToElement)) {
196+
console.warn(`Element matching '[cdkFocusInitial]' is not focusable.`, redirectToElement);
197+
}
198+
192199
redirectToElement.focus();
193200
return true;
194201
}

0 commit comments

Comments
 (0)