Skip to content

Commit 4e12072

Browse files
crisbetokara
authored andcommitted
fix(dialog): move focus into container if no focusable elements are found (#6524)
Fixes #6513.
1 parent e0b1094 commit 4e12072

File tree

3 files changed

+27
-3
lines changed

3 files changed

+27
-3
lines changed

src/lib/dialog/dialog-container.ts

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,6 +65,7 @@ export function throwMdDialogContentAlreadyAttachedError() {
6565
],
6666
host: {
6767
'class': 'mat-dialog-container',
68+
'tabindex': '-1',
6869
'[attr.role]': '_config?.role',
6970
'[attr.aria-labelledby]': '_ariaLabelledBy',
7071
'[attr.aria-describedby]': '_config?.ariaDescribedBy || null',
@@ -143,7 +144,13 @@ export class MdDialogContainer extends BasePortalHost {
143144
// If were to attempt to focus immediately, then the content of the dialog would not yet be
144145
// ready in instances where change detection has to run first. To deal with this, we simply
145146
// wait for the microtask queue to be empty.
146-
this._focusTrap.focusInitialElementWhenReady();
147+
this._focusTrap.focusInitialElementWhenReady().then(hasMovedFocus => {
148+
// If we didn't find any focusable elements inside the dialog, focus the
149+
// container so the user can't tab into other elements behind it.
150+
if (!hasMovedFocus) {
151+
this._elementRef.nativeElement.focus();
152+
}
153+
});
147154
}
148155

149156
/** Restores focus to the element that was focused before the dialog opened. */

src/lib/dialog/dialog.scss

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,7 @@ $mat-dialog-button-margin: 8px !default;
1717
box-sizing: border-box;
1818
overflow: auto;
1919
max-width: $mat-dialog-max-width;
20+
outline: 0;
2021

2122
// The dialog container should completely fill its parent overlay element.
2223
width: 100%;

src/lib/dialog/dialog.spec.ts

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -721,6 +721,17 @@ describe('MdDialog', () => {
721721
document.body.removeChild(input);
722722
}));
723723

724+
it('should move focus to the container if there are no focusable elements in the dialog',
725+
fakeAsync(() => {
726+
dialog.open(DialogWithoutFocusableElements);
727+
728+
viewContainerFixture.detectChanges();
729+
flushMicrotasks();
730+
731+
expect(document.activeElement.tagName)
732+
.toBe('MD-DIALOG-CONTAINER', 'Expected dialog container to be focused.');
733+
}));
734+
724735
});
725736

726737
describe('dialog content elements', () => {
@@ -952,6 +963,9 @@ class DialogWithInjectedData {
952963
constructor(@Inject(MD_DIALOG_DATA) public data: any) { }
953964
}
954965

966+
@Component({template: '<p>Pasta</p>'})
967+
class DialogWithoutFocusableElements {}
968+
955969
// Create a real (non-test) NgModule as a workaround for
956970
// https://github.com/angular/angular/issues/10760
957971
const TEST_DIRECTIVES = [
@@ -961,7 +975,8 @@ const TEST_DIRECTIVES = [
961975
DirectiveWithViewContainer,
962976
ComponentWithOnPushViewContainer,
963977
ContentElementDialog,
964-
DialogWithInjectedData
978+
DialogWithInjectedData,
979+
DialogWithoutFocusableElements
965980
];
966981

967982
@NgModule({
@@ -973,7 +988,8 @@ const TEST_DIRECTIVES = [
973988
ComponentWithTemplateRef,
974989
PizzaMsg,
975990
ContentElementDialog,
976-
DialogWithInjectedData
991+
DialogWithInjectedData,
992+
DialogWithoutFocusableElements,
977993
],
978994
})
979995
class DialogTestModule { }

0 commit comments

Comments
 (0)