diff --git a/src/lib/core/a11y/focus-trap.spec.ts b/src/lib/core/a11y/focus-trap.spec.ts index 80a72e1b0f0a..49900604f4ff 100644 --- a/src/lib/core/a11y/focus-trap.spec.ts +++ b/src/lib/core/a11y/focus-trap.spec.ts @@ -9,7 +9,13 @@ describe('FocusTrap', () => { beforeEach(async(() => { TestBed.configureTestingModule({ - declarations: [FocusTrapDirective, FocusTrapWithBindings, SimpleFocusTrap, FocusTrapTargets], + declarations: [ + FocusTrapDirective, + FocusTrapWithBindings, + SimpleFocusTrap, + FocusTrapTargets, + FocusTrapWithSvg + ], providers: [InteractivityChecker, Platform, FocusTrapFactory] }); @@ -112,6 +118,20 @@ describe('FocusTrap', () => { expect(document.activeElement.id).toBe('last'); }); }); + + describe('special cases', () => { + it('should not throw when it has a SVG child', () => { + let fixture = TestBed.createComponent(FocusTrapWithSvg); + + fixture.detectChanges(); + + let focusTrapInstance = fixture.componentInstance.focusTrapDirective.focusTrap; + + expect(() => focusTrapInstance.focusFirstTabbableElement()).not.toThrow(); + expect(() => focusTrapInstance.focusLastTabbableElement()).not.toThrow(); + }); + }); + }); @@ -156,3 +176,17 @@ class FocusTrapWithBindings { class FocusTrapTargets { @ViewChild(FocusTrapDirective) focusTrapDirective: FocusTrapDirective; } + + +@Component({ + template: ` +
+ + + +
+ ` +}) +class FocusTrapWithSvg { + @ViewChild(FocusTrapDirective) focusTrapDirective: FocusTrapDirective; +} diff --git a/src/lib/core/a11y/focus-trap.ts b/src/lib/core/a11y/focus-trap.ts index c2d4c95b2d5d..cd4fb72780d4 100644 --- a/src/lib/core/a11y/focus-trap.ts +++ b/src/lib/core/a11y/focus-trap.ts @@ -128,10 +128,15 @@ export class FocusTrap { return root; } - // Iterate in DOM order. - let childCount = root.children.length; - for (let i = 0; i < childCount; i++) { - let tabbableChild = this._getFirstTabbableElement(root.children[i] as HTMLElement); + // Iterate in DOM order. Note that IE doesn't have `children` for SVG so we fall + // back to `childNodes` which includes text nodes, comments etc. + let children = root.children || root.childNodes; + + for (let i = 0; i < children.length; i++) { + let tabbableChild = children[i].nodeType === Node.ELEMENT_NODE ? + this._getFirstTabbableElement(children[i] as HTMLElement) : + null; + if (tabbableChild) { return tabbableChild; } @@ -147,8 +152,13 @@ export class FocusTrap { } // Iterate in reverse DOM order. - for (let i = root.children.length - 1; i >= 0; i--) { - let tabbableChild = this._getLastTabbableElement(root.children[i] as HTMLElement); + let children = root.children || root.childNodes; + + for (let i = children.length - 1; i >= 0; i--) { + let tabbableChild = children[i].nodeType === Node.ELEMENT_NODE ? + this._getLastTabbableElement(children[i] as HTMLElement) : + null; + if (tabbableChild) { return tabbableChild; }