Skip to content

Commit d06ad75

Browse files
crisbetotinayuangao
authored andcommitted
fix(focus-trap): exception when element contains SVG on IE (#3432)
Fixes an exception being thrown by the focus trap, if it contains an SVG element on IE. The problem was that on IE, SVG elements don't have the `children` property, which means that we have to fall back to `childNodes`. Fixes #3410.
1 parent 842896b commit d06ad75

File tree

2 files changed

+51
-7
lines changed

2 files changed

+51
-7
lines changed

src/lib/core/a11y/focus-trap.spec.ts

+35-1
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,13 @@ describe('FocusTrap', () => {
99

1010
beforeEach(async(() => {
1111
TestBed.configureTestingModule({
12-
declarations: [FocusTrapDirective, FocusTrapWithBindings, SimpleFocusTrap, FocusTrapTargets],
12+
declarations: [
13+
FocusTrapDirective,
14+
FocusTrapWithBindings,
15+
SimpleFocusTrap,
16+
FocusTrapTargets,
17+
FocusTrapWithSvg
18+
],
1319
providers: [InteractivityChecker, Platform, FocusTrapFactory]
1420
});
1521

@@ -112,6 +118,20 @@ describe('FocusTrap', () => {
112118
expect(document.activeElement.id).toBe('last');
113119
});
114120
});
121+
122+
describe('special cases', () => {
123+
it('should not throw when it has a SVG child', () => {
124+
let fixture = TestBed.createComponent(FocusTrapWithSvg);
125+
126+
fixture.detectChanges();
127+
128+
let focusTrapInstance = fixture.componentInstance.focusTrapDirective.focusTrap;
129+
130+
expect(() => focusTrapInstance.focusFirstTabbableElement()).not.toThrow();
131+
expect(() => focusTrapInstance.focusLastTabbableElement()).not.toThrow();
132+
});
133+
});
134+
115135
});
116136

117137

@@ -156,3 +176,17 @@ class FocusTrapWithBindings {
156176
class FocusTrapTargets {
157177
@ViewChild(FocusTrapDirective) focusTrapDirective: FocusTrapDirective;
158178
}
179+
180+
181+
@Component({
182+
template: `
183+
<div cdkTrapFocus>
184+
<svg xmlns="http://www.w3.org/2000/svg">
185+
<circle cx="100" cy="100" r="100"/>
186+
</svg>
187+
</div>
188+
`
189+
})
190+
class FocusTrapWithSvg {
191+
@ViewChild(FocusTrapDirective) focusTrapDirective: FocusTrapDirective;
192+
}

src/lib/core/a11y/focus-trap.ts

+16-6
Original file line numberDiff line numberDiff line change
@@ -128,10 +128,15 @@ export class FocusTrap {
128128
return root;
129129
}
130130

131-
// Iterate in DOM order.
132-
let childCount = root.children.length;
133-
for (let i = 0; i < childCount; i++) {
134-
let tabbableChild = this._getFirstTabbableElement(root.children[i] as HTMLElement);
131+
// Iterate in DOM order. Note that IE doesn't have `children` for SVG so we fall
132+
// back to `childNodes` which includes text nodes, comments etc.
133+
let children = root.children || root.childNodes;
134+
135+
for (let i = 0; i < children.length; i++) {
136+
let tabbableChild = children[i].nodeType === Node.ELEMENT_NODE ?
137+
this._getFirstTabbableElement(children[i] as HTMLElement) :
138+
null;
139+
135140
if (tabbableChild) {
136141
return tabbableChild;
137142
}
@@ -147,8 +152,13 @@ export class FocusTrap {
147152
}
148153

149154
// Iterate in reverse DOM order.
150-
for (let i = root.children.length - 1; i >= 0; i--) {
151-
let tabbableChild = this._getLastTabbableElement(root.children[i] as HTMLElement);
155+
let children = root.children || root.childNodes;
156+
157+
for (let i = children.length - 1; i >= 0; i--) {
158+
let tabbableChild = children[i].nodeType === Node.ELEMENT_NODE ?
159+
this._getLastTabbableElement(children[i] as HTMLElement) :
160+
null;
161+
152162
if (tabbableChild) {
153163
return tabbableChild;
154164
}

0 commit comments

Comments
 (0)