-
Notifications
You must be signed in to change notification settings - Fork 791
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat(is-in-tab-order): add isInTabOrder to commons (#3619)
* add commons.isInTabOrder() * replace uses of isFocusable with isInTabOrder when isFocusable also checked for negative tabindex references: #3500 Co-authored-by: Wilco Fiers <WilcoFiers@users.noreply.github.com> Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com>
- Loading branch information
1 parent
b16f553
commit 77afe90
Showing
5 changed files
with
131 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import AbstractVirtualNode from '../../core/base/virtual-node/abstract-virtual-node'; | ||
import { getNodeFromTree } from '../../core/utils'; | ||
import isFocusable from './is-focusable'; | ||
|
||
/** | ||
* Determines if an element is focusable and able to be tabbed to. | ||
* @method isInTabOrder | ||
* @memberof axe.commons.dom | ||
* @instance | ||
* @param {HTMLElement} el The HTMLElement | ||
* @return {Boolean} The element's tabindex status | ||
*/ | ||
export default function isInTabOrder(el) { | ||
const vNode = el instanceof AbstractVirtualNode ? el : getNodeFromTree(el); | ||
|
||
if (vNode.props.nodeType !== 1) { | ||
return false; | ||
} | ||
|
||
const tabindex = parseInt(vNode.attr('tabindex', 10)); | ||
if (tabindex <= -1) { | ||
return false; // Elements with tabindex=-1 are never in the tab order | ||
} | ||
|
||
return isFocusable(vNode); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,100 @@ | ||
describe('dom.isInTabOrder', function () { | ||
'use strict'; | ||
|
||
var queryFixture = axe.testUtils.queryFixture; | ||
var isInTabOrder = axe.commons.dom.isInTabOrder; | ||
var isIE11 = axe.testUtils.isIE11; | ||
|
||
it('should return false for presentation element with negative tabindex', function () { | ||
var target = queryFixture('<div id="target" tabindex="-1"></div>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return true for presentation element with positive tabindex', function () { | ||
var target = queryFixture('<div id="target" tabindex="1"></div>'); | ||
assert.isTrue(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for presentation element with tabindex not set', function () { | ||
var target = queryFixture('<div id="target"></div>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for presentation element with tabindex set to non-parseable value', function () { | ||
var target = queryFixture('<div id="target" tabindex="foobar"></div>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for presentation element with tabindex not set and role of natively focusable element', function () { | ||
var target = queryFixture('<div id="target" role="button"></div>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return true for natively focusable element with tabindex 0', function () { | ||
var target = queryFixture('<button id="target" tabindex="0"></button>'); | ||
assert.isTrue(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return true for natively focusable element with tabindex 1', function () { | ||
var target = queryFixture('<button id="target" tabindex="1"></button>'); | ||
assert.isTrue(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for natively focusable element with tabindex -1', function () { | ||
var target = queryFixture('<button id="target" tabindex="-1"></button>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return true for natively focusable element with tabindex not set', function () { | ||
var target = queryFixture('<button id="target"></button>'); | ||
assert.isTrue(isInTabOrder(target)); | ||
}); | ||
|
||
// IE11 returns a negative tabindex for elements with tabindex set to an empty string, rather than create false positives, skip it | ||
(isIE11 ? xit : it)( | ||
'should return true for natively focusable element with tabindex set to empty string', | ||
function () { | ||
var target = queryFixture('<button id="target" tabindex=""></button>'); | ||
assert.isTrue(isInTabOrder(target)); | ||
} | ||
); | ||
|
||
it('should return true for natively focusable element with tabindex set to non-parseable value', function () { | ||
var target = queryFixture( | ||
'<button id="target" tabindex="foobar"></button>' | ||
); | ||
assert.isTrue(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for disabled', function () { | ||
var target = queryFixture('<button id="target" disabled></button>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for disabled natively focusable element with tabindex', function () { | ||
var target = queryFixture( | ||
'<button id="target" disabled tabindex="0"></button>' | ||
); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for hidden inputs', function () { | ||
var target = queryFixture('<input type="hidden" id="target"></input>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return false for non-element nodes', function () { | ||
var target = queryFixture('<span id="target">Hello World</span>'); | ||
assert.isFalse(isInTabOrder(target.children[0])); | ||
}); | ||
|
||
it('should return false for natively focusable hidden element', function () { | ||
var target = queryFixture('<button id="target" hidden></button>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
|
||
it('should return for false hidden element with tabindex 1', function () { | ||
var target = queryFixture('<div id="target" tabindex="1" hidden></div>'); | ||
assert.isFalse(isInTabOrder(target)); | ||
}); | ||
}); |