diff --git a/lib/checks/keyboard/frame-focusable-content-evaluate.js b/lib/checks/keyboard/frame-focusable-content-evaluate.js index 0624167778..5c746c9347 100644 --- a/lib/checks/keyboard/frame-focusable-content-evaluate.js +++ b/lib/checks/keyboard/frame-focusable-content-evaluate.js @@ -1,7 +1,26 @@ import isFocusable from '../../commons/dom/is-focusable'; +export default function frameFocusableContentEvaluate( + node, + options, + virtualNode +) { + if (!virtualNode.children) { + return undefined; + } + + try { + return !virtualNode.children.some(child => { + return focusableDescendants(child); + }); + } catch (e) { + return undefined; + } +} + function focusableDescendants(vNode) { - if (isFocusable(vNode)) { + const tabIndex = parseInt(vNode.attr('tabindex'), 10); + if ((isNaN(tabIndex) || tabIndex > -1) && isFocusable(vNode)) { return true; } @@ -17,19 +36,3 @@ function focusableDescendants(vNode) { return focusableDescendants(child); }); } - -function frameFocusableContentEvaluate(node, options, virtualNode) { - if (!virtualNode.children) { - return undefined; - } - - try { - return !virtualNode.children.some(child => { - return focusableDescendants(child); - }); - } catch (e) { - return undefined; - } -} - -export default frameFocusableContentEvaluate; diff --git a/lib/commons/dom/is-focusable.js b/lib/commons/dom/is-focusable.js index d5900b4e27..6fc676fa10 100644 --- a/lib/commons/dom/is-focusable.js +++ b/lib/commons/dom/is-focusable.js @@ -4,15 +4,14 @@ import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-n import { getNodeFromTree } from '../../core/utils'; /** - * Determines if an element is focusable + * Determines if an element is keyboard or programmatically focusable. * @method isFocusable * @memberof axe.commons.dom * @instance * @param {HTMLElement} el The HTMLElement * @return {Boolean} The element's focusability status */ - -function isFocusable(el) { +export default function isFocusable(el) { const vNode = el instanceof AbstractVirtualNode ? el : getNodeFromTree(el); if (vNode.props.nodeType !== 1) { @@ -32,5 +31,3 @@ function isFocusable(el) { return false; } - -export default isFocusable; diff --git a/test/checks/keyboard/frame-focusable-content.js b/test/checks/keyboard/frame-focusable-content.js index 224667aa6e..acac4d497c 100644 --- a/test/checks/keyboard/frame-focusable-content.js +++ b/test/checks/keyboard/frame-focusable-content.js @@ -10,32 +10,45 @@ describe('frame-focusable-content tests', function() { }); it('should return true if element has no focusable content', function() { - var vNode = queryFixture(''); + var vNode = queryFixture('
Hello
'); assert.isTrue(frameFocusableContent(null, null, vNode)); }); it('should return true if element is empty', function() { - var vNode = queryFixture(''); + var vNode = queryFixture('
'); assert.isTrue(frameFocusableContent(null, null, vNode)); }); it('should return true if element only has text content', function() { - var vNode = queryFixture(''); + var vNode = queryFixture('
Hello
'); assert.isTrue(frameFocusableContent(null, null, vNode)); }); it('should return false if element has focusable content', function() { var vNode = queryFixture( - '' + '
Hello
' ); assert.isFalse(frameFocusableContent(null, null, vNode)); }); it('should return false if element has natively focusable content', function() { var vNode = queryFixture( - '' + '
Hello
' + ); + assert.isFalse(frameFocusableContent(null, null, vNode)); + }); + + it('should return true if element is natively focusable but has tabindex=-1', function() { + var vNode = queryFixture( + '
' + ); + assert.isTrue(frameFocusableContent(null, null, vNode)); + }); + + it('should return false if element is natively focusable but has tabindex=0', function() { + var vNode = queryFixture( + '
' ); assert.isFalse(frameFocusableContent(null, null, vNode)); }); - }); diff --git a/test/integration/rules/frame-focusable-content/frame-focusable-content.html b/test/integration/rules/frame-focusable-content/frame-focusable-content.html index c10c6d130f..f61fdba0be 100644 --- a/test/integration/rules/frame-focusable-content/frame-focusable-content.html +++ b/test/integration/rules/frame-focusable-content/frame-focusable-content.html @@ -3,6 +3,11 @@ tabindex="-1" id="pass1" > +