From 2467b3a59cb853689b88a15580acd6e9b210dd6b Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Thu, 19 Aug 2021 21:12:04 -0400 Subject: [PATCH 01/28] refactor(checks/navigation): improve `internal-link-present-evaluate` Make `internal-link-present-evaluate` work with virtualNode rather than actualNode. Closes issue #2466 --- .../internal-link-present-evaluate.js | 20 +-- .../navigation/internal-link-present.js | 155 +++++++++--------- 2 files changed, 88 insertions(+), 87 deletions(-) diff --git a/lib/checks/navigation/internal-link-present-evaluate.js b/lib/checks/navigation/internal-link-present-evaluate.js index acf086d43f..d235bfbe2b 100644 --- a/lib/checks/navigation/internal-link-present-evaluate.js +++ b/lib/checks/navigation/internal-link-present-evaluate.js @@ -1,10 +1,10 @@ -import { querySelectorAll } from '../../core/utils'; - -function internalLinkPresentEvaluate(node, options, virtualNode) { - const links = querySelectorAll(virtualNode, 'a[href]'); - return links.some(vLink => { - return /^#[^/!]/.test(vLink.actualNode.getAttribute('href')); - }); -} - -export default internalLinkPresentEvaluate; +import { querySelectorAll } from '../../core/utils'; + +function internalLinkPresentEvaluate(node, options, virtualNode) { + const links = querySelectorAll(virtualNode, 'a[href]'); + return links.some(vLink => { + return /^#[^/!]/.test(vLink.attr('href')); + }); +} + +export default internalLinkPresentEvaluate; diff --git a/test/checks/navigation/internal-link-present.js b/test/checks/navigation/internal-link-present.js index 5ea7efed12..2f3d34d561 100644 --- a/test/checks/navigation/internal-link-present.js +++ b/test/checks/navigation/internal-link-present.js @@ -1,77 +1,78 @@ -describe('internal-link-present', function() { - 'use strict'; - - var fixture = document.getElementById('fixture'); - var shadowSupported = axe.testUtils.shadowSupport.v1; - var checkContext = axe.testUtils.MockCheckContext(); - var checkSetup = axe.testUtils.checkSetup; - var shadowCheckSetup = axe.testUtils.shadowCheckSetup; - - afterEach(function() { - fixture.innerHTML = ''; - axe._tree = undefined; - checkContext.reset(); - }); - - it('should return true when an internal link is found', function() { - var params = checkSetup('
hi
'); - assert.isTrue( - axe.testUtils - .getCheckEvaluate('internal-link-present') - .apply(checkContext, params) - ); - }); - - it('should return false when a hashbang URL was used', function() { - var params = checkSetup('
hi
'); - assert.isFalse( - axe.testUtils - .getCheckEvaluate('internal-link-present') - .apply(checkContext, params) - ); - }); - - it('should return false when a hash route URL was used', function() { - var params = checkSetup('
hi
'); - assert.isFalse( - axe.testUtils - .getCheckEvaluate('internal-link-present') - .apply(checkContext, params) - ); - }); - - it('should return false when a hashbang + slash route URL was used', function() { - var params = checkSetup('
hi
'); - assert.isFalse( - axe.testUtils - .getCheckEvaluate('internal-link-present') - .apply(checkContext, params) - ); - }); - - it('should otherwise return false', function() { - var params = checkSetup( - '
hi
' - ); - assert.isFalse( - axe.testUtils - .getCheckEvaluate('internal-link-present') - .apply(checkContext, params) - ); - }); - - (shadowSupported ? it : xit)( - 'should return true when internal link is found in shadow dom', - function() { - var params = shadowCheckSetup( - '
', - 'hi' - ); - assert.isTrue( - axe.testUtils - .getCheckEvaluate('internal-link-present') - .apply(checkContext, params) - ); - } - ); -}); +describe('internal-link-present', function() { + 'use strict'; + + var fixture = document.getElementById('fixture'); + var shadowSupported = axe.testUtils.shadowSupport.v1; + var checkContext = axe.testUtils.MockCheckContext(); + var shadowCheckSetup = axe.testUtils.shadowCheckSetup; + var queryFixture = axe.testUtils.queryFixture; + + afterEach(function() { + fixture.innerHTML = ''; + axe._tree = undefined; + checkContext.reset(); + }); + + it('should return true when an internal link is found', function() { + var vNode = queryFixture('
hi
'); + assert.isTrue( + axe.testUtils + .getCheckEvaluate('internal-link-present') + .call(checkContext, null, {}, vNode) + ); + }); + + it('should return false when a hashbang URL was used', function() { + var vNode = queryFixture('
hi
'); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('internal-link-present') + .call(checkContext, null, {}, vNode) + ); + }); + + it('should return false when a hash route URL was used', function() { + var vNode = queryFixture('
hi
'); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('internal-link-present') + .call(checkContext, null, {}, vNode) + ); + }); + + it('should return false when a hashbang + slash route URL was used', function() { + var vNode = queryFixture('
hi
'); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('internal-link-present') + .call(checkContext, null, {}, vNode) + ); + }); + + it('should otherwise return false', function() { + var vNode = queryFixture( + '
hi
' + ); + assert.isFalse( + axe.testUtils + .getCheckEvaluate('internal-link-present') + .call(checkContext, null, {}, vNode) + ); + }); + + (shadowSupported ? it : xit)( + 'should return true when internal link is found in shadow dom', + function() { + var params = shadowCheckSetup( + '
', + 'hi' + ); + var vNode = params[2]; + assert.isTrue( + axe.testUtils + .getCheckEvaluate('internal-link-present') + .call(checkContext, null, {}, vNode) + ); + } + ); +}); From 9f996bc6f54092541db77b9c3e62e2a5d9d9643e Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Fri, 3 Sep 2021 08:48:36 -0400 Subject: [PATCH 02/28] test commit 1 --- test/testutils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/testutils.js b/test/testutils.js index 8c60d13a93..5b37f8b83d 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -501,3 +501,6 @@ testUtils.shadowQuerySelector = function shadowQuerySelector(axeSelector, doc) { }); return elm; }; + +// test commit 1 + From c011d2c2887c2caecb53e40411b4526d0f0690e9 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Fri, 3 Sep 2021 08:54:37 -0400 Subject: [PATCH 03/28] test commit 2 --- test/testutils.js | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test/testutils.js b/test/testutils.js index 8c60d13a93..a31429c124 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -501,3 +501,6 @@ testUtils.shadowQuerySelector = function shadowQuerySelector(axeSelector, doc) { }); return elm; }; + +// test commit 2 + From a3861666d61988443343356a8b26760cc3818a6e Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Fri, 3 Sep 2021 08:55:07 -0400 Subject: [PATCH 04/28] test commit 3 --- test/testutils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testutils.js b/test/testutils.js index a31429c124..f5b385e6d5 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -502,5 +502,5 @@ testUtils.shadowQuerySelector = function shadowQuerySelector(axeSelector, doc) { return elm; }; -// test commit 2 +// test commit 3 From 31b19a3829bd8d52eacc006af973261e2d4d1f93 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Fri, 3 Sep 2021 09:28:17 -0400 Subject: [PATCH 05/28] Revert "Merge branch 'dan-test-branch-1' into develop" This reverts commit 428e01533eb561a5a2ee0a603014057337ba0177, reversing changes made to 9f996bc6f54092541db77b9c3e62e2a5d9d9643e. --- test/testutils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/test/testutils.js b/test/testutils.js index 73d902ed24..5b37f8b83d 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -502,5 +502,5 @@ testUtils.shadowQuerySelector = function shadowQuerySelector(axeSelector, doc) { return elm; }; -// test commit 1 & 3 +// test commit 1 From ac32146f5561fcdafac1c5876e57f3fd8342d8a0 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Fri, 3 Sep 2021 09:28:29 -0400 Subject: [PATCH 06/28] Revert "test commit 1" This reverts commit 9f996bc6f54092541db77b9c3e62e2a5d9d9643e. --- test/testutils.js | 3 --- 1 file changed, 3 deletions(-) diff --git a/test/testutils.js b/test/testutils.js index 5b37f8b83d..8c60d13a93 100644 --- a/test/testutils.js +++ b/test/testutils.js @@ -501,6 +501,3 @@ testUtils.shadowQuerySelector = function shadowQuerySelector(axeSelector, doc) { }); return elm; }; - -// test commit 1 - From 30f0e01506979bb92600289bd242ab01d25cb8ec Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Thu, 23 Sep 2021 21:12:17 -0400 Subject: [PATCH 07/28] fix(rule): allow "tabindex=-1" for rules "aria-text" and "nested-interactive" Closes issue #2934 --- .../keyboard/no-focusable-content-evaluate.js | 6 ++++- test/checks/keyboard/no-focusable-content.js | 22 +++++++++++++++++++ .../rules/aria-text/aria-text.html | 6 ++--- .../rules/aria-text/aria-text.json | 4 ++-- .../nested-interactive.html | 12 +++++----- .../nested-interactive.json | 4 +++- .../virtual-rules/nested-interactive.js | 20 +++++++++++++++++ 7 files changed, 62 insertions(+), 12 deletions(-) diff --git a/lib/checks/keyboard/no-focusable-content-evaluate.js b/lib/checks/keyboard/no-focusable-content-evaluate.js index e45bdfde9f..0f6842405f 100644 --- a/lib/checks/keyboard/no-focusable-content-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-evaluate.js @@ -1,7 +1,11 @@ import isFocusable from '../../commons/dom/is-focusable'; function focusableDescendants(vNode) { - if (isFocusable(vNode)) { + const isNodeFocusable = isFocusable(vNode); + let tabIndex = parseInt(vNode.attr('tabindex'), 10); + tabIndex = !isNaN(tabIndex) ? tabIndex : null; + + if(tabIndex ? isNodeFocusable && tabIndex >= 0 : isNodeFocusable) { return true; } diff --git a/test/checks/keyboard/no-focusable-content.js b/test/checks/keyboard/no-focusable-content.js index 1e1a3a8474..9959fda468 100644 --- a/test/checks/keyboard/no-focusable-content.js +++ b/test/checks/keyboard/no-focusable-content.js @@ -37,4 +37,26 @@ describe('no-focusable-content tests', function() { ); assert.isFalse(noFocusableContent(null, null, vNode)); }); + + it('should return true on span with tabindex=-1', function() { + var vNode = queryFixture(' some text ' + +'JavaScript is able to focus this ' + +''); + assert.isTrue(noFocusableContent(null, null, vNode)); + }); + + it('should return true on aria-hidden span with tabindex=-1', function() { + var vNode = queryFixture(' some text ' + +' ' + +''); + assert.isTrue(noFocusableContent(null, null, vNode)); + }); + + it('should return false on span with tabindex=0', function() { + var vNode = queryFixture(' some text ' + +'anyone is able to focus this ' + +''); + assert.isFalse(noFocusableContent(null, null, vNode)); + }); + }); diff --git a/test/integration/rules/aria-text/aria-text.html b/test/integration/rules/aria-text/aria-text.html index 28252c0bce..4059f1e53b 100644 --- a/test/integration/rules/aria-text/aria-text.html +++ b/test/integration/rules/aria-text/aria-text.html @@ -15,8 +15,8 @@

Flattened text because of the explicit role.
-
+
Flattened text because of the - explicit role. + explicit role. Considered non-focusable because of tabindex=-1...
-

+

diff --git a/test/integration/rules/aria-text/aria-text.json b/test/integration/rules/aria-text/aria-text.json index f6c3f1d2d9..3aa00ff23b 100644 --- a/test/integration/rules/aria-text/aria-text.json +++ b/test/integration/rules/aria-text/aria-text.json @@ -1,6 +1,6 @@ { "description": "aria-text tests", "rule": "aria-text", - "violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"]], - "passes": [["#pass1"], ["#pass2"], ["#pass3"]] + "violations": [["#fail1"], ["#fail2"], ["#fail3"]], + "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]] } diff --git a/test/integration/rules/nested-interactive/nested-interactive.html b/test/integration/rules/nested-interactive/nested-interactive.html index beb7fbdf37..0baf57f5bb 100644 --- a/test/integration/rules/nested-interactive/nested-interactive.html +++ b/test/integration/rules/nested-interactive/nested-interactive.html @@ -1,12 +1,14 @@ -
pass
- - - + +
pass
+ + + +
- + diff --git a/test/integration/rules/nested-interactive/nested-interactive.json b/test/integration/rules/nested-interactive/nested-interactive.json index 78d3b43176..9195a46ad1 100644 --- a/test/integration/rules/nested-interactive/nested-interactive.json +++ b/test/integration/rules/nested-interactive/nested-interactive.json @@ -8,6 +8,8 @@ ["#pass3"], ["#pass4"], ["#pass5"], - ["#pass6"] + ["#pass6"], + ["#pass7"], + ["#pass8"] ] } diff --git a/test/integration/virtual-rules/nested-interactive.js b/test/integration/virtual-rules/nested-interactive.js index ba963b99b5..cd364e2b22 100644 --- a/test/integration/virtual-rules/nested-interactive.js +++ b/test/integration/virtual-rules/nested-interactive.js @@ -38,6 +38,26 @@ describe('nested-interactive virtual-rule', function() { assert.lengthOf(results.incomplete, 0); }); + it('should pass for element with content with tabindex=-1', function() { + var node = new axe.SerialVirtualNode({ + nodeName: 'button' + }); + var child = new axe.SerialVirtualNode({ + nodeName: 'span', + attributes: { + tabindex: -1 + } + }); + child.children = []; + node.children = [child]; + + var results = axe.runVirtualRule('nested-interactive', node); + + assert.lengthOf(results.passes, 1); + assert.lengthOf(results.violations, 0); + assert.lengthOf(results.incomplete, 0); + }); + it('should pass for empty element without', function() { var node = new axe.SerialVirtualNode({ nodeName: 'div', From 86ac3277152faf41c753e427c9fba6fdd602bcd1 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Fri, 1 Oct 2021 08:33:34 -0400 Subject: [PATCH 08/28] Revert "fix(rule): allow "tabindex=-1" for rules "aria-text" and "nested-interactive"" This reverts commit 30f0e01506979bb92600289bd242ab01d25cb8ec. --- .../keyboard/no-focusable-content-evaluate.js | 6 +---- test/checks/keyboard/no-focusable-content.js | 22 ------------------- .../rules/aria-text/aria-text.html | 6 ++--- .../rules/aria-text/aria-text.json | 4 ++-- .../nested-interactive.html | 12 +++++----- .../nested-interactive.json | 4 +--- .../virtual-rules/nested-interactive.js | 20 ----------------- 7 files changed, 12 insertions(+), 62 deletions(-) diff --git a/lib/checks/keyboard/no-focusable-content-evaluate.js b/lib/checks/keyboard/no-focusable-content-evaluate.js index 0f6842405f..e45bdfde9f 100644 --- a/lib/checks/keyboard/no-focusable-content-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-evaluate.js @@ -1,11 +1,7 @@ import isFocusable from '../../commons/dom/is-focusable'; function focusableDescendants(vNode) { - const isNodeFocusable = isFocusable(vNode); - let tabIndex = parseInt(vNode.attr('tabindex'), 10); - tabIndex = !isNaN(tabIndex) ? tabIndex : null; - - if(tabIndex ? isNodeFocusable && tabIndex >= 0 : isNodeFocusable) { + if (isFocusable(vNode)) { return true; } diff --git a/test/checks/keyboard/no-focusable-content.js b/test/checks/keyboard/no-focusable-content.js index 9959fda468..1e1a3a8474 100644 --- a/test/checks/keyboard/no-focusable-content.js +++ b/test/checks/keyboard/no-focusable-content.js @@ -37,26 +37,4 @@ describe('no-focusable-content tests', function() { ); assert.isFalse(noFocusableContent(null, null, vNode)); }); - - it('should return true on span with tabindex=-1', function() { - var vNode = queryFixture(' some text ' - +'JavaScript is able to focus this ' - +''); - assert.isTrue(noFocusableContent(null, null, vNode)); - }); - - it('should return true on aria-hidden span with tabindex=-1', function() { - var vNode = queryFixture(' some text ' - +' ' - +''); - assert.isTrue(noFocusableContent(null, null, vNode)); - }); - - it('should return false on span with tabindex=0', function() { - var vNode = queryFixture(' some text ' - +'anyone is able to focus this ' - +''); - assert.isFalse(noFocusableContent(null, null, vNode)); - }); - }); diff --git a/test/integration/rules/aria-text/aria-text.html b/test/integration/rules/aria-text/aria-text.html index 4059f1e53b..28252c0bce 100644 --- a/test/integration/rules/aria-text/aria-text.html +++ b/test/integration/rules/aria-text/aria-text.html @@ -15,8 +15,8 @@

Flattened text because of the explicit role.
-
+
Flattened text because of the - explicit role. Considered non-focusable because of tabindex=-1... + explicit role.
-

+

diff --git a/test/integration/rules/aria-text/aria-text.json b/test/integration/rules/aria-text/aria-text.json index 3aa00ff23b..f6c3f1d2d9 100644 --- a/test/integration/rules/aria-text/aria-text.json +++ b/test/integration/rules/aria-text/aria-text.json @@ -1,6 +1,6 @@ { "description": "aria-text tests", "rule": "aria-text", - "violations": [["#fail1"], ["#fail2"], ["#fail3"]], - "passes": [["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"]] + "violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"]], + "passes": [["#pass1"], ["#pass2"], ["#pass3"]] } diff --git a/test/integration/rules/nested-interactive/nested-interactive.html b/test/integration/rules/nested-interactive/nested-interactive.html index 0baf57f5bb..beb7fbdf37 100644 --- a/test/integration/rules/nested-interactive/nested-interactive.html +++ b/test/integration/rules/nested-interactive/nested-interactive.html @@ -1,14 +1,12 @@ - -
pass
- - - - +
pass
+ + +
- + diff --git a/test/integration/rules/nested-interactive/nested-interactive.json b/test/integration/rules/nested-interactive/nested-interactive.json index 9195a46ad1..78d3b43176 100644 --- a/test/integration/rules/nested-interactive/nested-interactive.json +++ b/test/integration/rules/nested-interactive/nested-interactive.json @@ -8,8 +8,6 @@ ["#pass3"], ["#pass4"], ["#pass5"], - ["#pass6"], - ["#pass7"], - ["#pass8"] + ["#pass6"] ] } diff --git a/test/integration/virtual-rules/nested-interactive.js b/test/integration/virtual-rules/nested-interactive.js index cd364e2b22..ba963b99b5 100644 --- a/test/integration/virtual-rules/nested-interactive.js +++ b/test/integration/virtual-rules/nested-interactive.js @@ -38,26 +38,6 @@ describe('nested-interactive virtual-rule', function() { assert.lengthOf(results.incomplete, 0); }); - it('should pass for element with content with tabindex=-1', function() { - var node = new axe.SerialVirtualNode({ - nodeName: 'button' - }); - var child = new axe.SerialVirtualNode({ - nodeName: 'span', - attributes: { - tabindex: -1 - } - }); - child.children = []; - node.children = [child]; - - var results = axe.runVirtualRule('nested-interactive', node); - - assert.lengthOf(results.passes, 1); - assert.lengthOf(results.violations, 0); - assert.lengthOf(results.incomplete, 0); - }); - it('should pass for empty element without', function() { var node = new axe.SerialVirtualNode({ nodeName: 'div', From f97495514ea5149bf204bd99da470da45cb38b3d Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Sun, 3 Oct 2021 16:01:15 -0400 Subject: [PATCH 09/28] refactor(check): split no-focusable-content rule into three. That rule is now: no-focusable-content-for-aria-text, no-focusable-content-for-nested-interactive, and no-focusable-content-for-frame These three are all copy-and-pastes of each other, so far. --- ...ocusable-content-for-aria-text-evaluate.js | 35 ++++++++++++++++ ...> no-focusable-content-for-aria-text.json} | 4 +- ...o-focusable-content-for-frame-evaluate.js} | 4 +- ...on => no-focusable-content-for-frame.json} | 4 +- ...content-for-nested-interactive-evaluate.js | 35 ++++++++++++++++ ...usable-content-for-nested-interactive.json | 12 ++++++ lib/core/base/metadata-function-map.js | 8 +++- lib/rules/aria-text.json | 2 +- lib/rules/frame-focusable-content.json | 2 +- lib/rules/nested-interactive.json | 2 +- ... => no-focusable-content-for-aria-text.js} | 17 ++++---- ...ocusable-content-for-nested-interactive.js | 41 +++++++++++++++++++ 12 files changed, 147 insertions(+), 19 deletions(-) create mode 100644 lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js rename lib/checks/keyboard/{no-focusable-content.json => no-focusable-content-for-aria-text.json} (70%) rename lib/checks/keyboard/{no-focusable-content-evaluate.js => no-focusable-content-for-frame-evaluate.js} (82%) rename lib/checks/keyboard/{frame-focusable-content.json => no-focusable-content-for-frame.json} (71%) create mode 100644 lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js create mode 100644 lib/checks/keyboard/no-focusable-content-for-nested-interactive.json rename test/checks/keyboard/{no-focusable-content.js => no-focusable-content-for-aria-text.js} (65%) create mode 100644 test/checks/keyboard/no-focusable-content-for-nested-interactive.js diff --git a/lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js b/lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js new file mode 100644 index 0000000000..fc2ef483bd --- /dev/null +++ b/lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js @@ -0,0 +1,35 @@ +import isFocusable from '../../commons/dom/is-focusable'; + +function focusableDescendants(vNode) { + if (isFocusable(vNode)) { + return true; + } + + if (!vNode.children) { + if (vNode.props.nodeType === 1) { + throw new Error('Cannot determine children'); + } + + return false; + } + + return vNode.children.some(child => { + return focusableDescendants(child); + }); +} + +function noFocusableContentForAriaTextEvaluate(node, options, virtualNode) { + if (!virtualNode.children) { + return undefined; + } + + try { + return !virtualNode.children.some(child => { + return focusableDescendants(child); + }); + } catch (e) { + return undefined; + } +} + +export default noFocusableContentForAriaTextEvaluate; diff --git a/lib/checks/keyboard/no-focusable-content.json b/lib/checks/keyboard/no-focusable-content-for-aria-text.json similarity index 70% rename from lib/checks/keyboard/no-focusable-content.json rename to lib/checks/keyboard/no-focusable-content-for-aria-text.json index a67554e6a8..4d89a75a63 100644 --- a/lib/checks/keyboard/no-focusable-content.json +++ b/lib/checks/keyboard/no-focusable-content-for-aria-text.json @@ -1,6 +1,6 @@ { - "id": "no-focusable-content", - "evaluate": "no-focusable-content-evaluate", + "id": "no-focusable-content-for-aria-text", + "evaluate": "no-focusable-content-for-aria-text-evaluate", "metadata": { "impact": "serious", "messages": { diff --git a/lib/checks/keyboard/no-focusable-content-evaluate.js b/lib/checks/keyboard/no-focusable-content-for-frame-evaluate.js similarity index 82% rename from lib/checks/keyboard/no-focusable-content-evaluate.js rename to lib/checks/keyboard/no-focusable-content-for-frame-evaluate.js index e45bdfde9f..ecbc419892 100644 --- a/lib/checks/keyboard/no-focusable-content-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-for-frame-evaluate.js @@ -18,7 +18,7 @@ function focusableDescendants(vNode) { }); } -function noFocusbleContentEvaluate(node, options, virtualNode) { +function noFocusableContentForFrameEvaluate(node, options, virtualNode) { if (!virtualNode.children) { return undefined; } @@ -32,4 +32,4 @@ function noFocusbleContentEvaluate(node, options, virtualNode) { } } -export default noFocusbleContentEvaluate; +export default noFocusableContentForFrameEvaluate; diff --git a/lib/checks/keyboard/frame-focusable-content.json b/lib/checks/keyboard/no-focusable-content-for-frame.json similarity index 71% rename from lib/checks/keyboard/frame-focusable-content.json rename to lib/checks/keyboard/no-focusable-content-for-frame.json index 5157665b2e..8f5e73c587 100644 --- a/lib/checks/keyboard/frame-focusable-content.json +++ b/lib/checks/keyboard/no-focusable-content-for-frame.json @@ -1,6 +1,6 @@ { - "id": "frame-focusable-content", - "evaluate": "no-focusable-content-evaluate", + "id": "no-focusable-content-for-frame", + "evaluate": "no-focusable-content-for-frame-evaluate", "metadata": { "impact": "serious", "messages": { diff --git a/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js b/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js new file mode 100644 index 0000000000..c68fb171fa --- /dev/null +++ b/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js @@ -0,0 +1,35 @@ +import isFocusable from '../../commons/dom/is-focusable'; + +function focusableDescendants(vNode) { + if (isFocusable(vNode)) { + return true; + } + + if (!vNode.children) { + if (vNode.props.nodeType === 1) { + throw new Error('Cannot determine children'); + } + + return false; + } + + return vNode.children.some(child => { + return focusableDescendants(child); + }); +} + +function noFocusableContentForNestedInteractiveEvaluate(node, options, virtualNode) { + if (!virtualNode.children) { + return undefined; + } + + try { + return !virtualNode.children.some(child => { + return focusableDescendants(child); + }); + } catch (e) { + return undefined; + } +} + +export default noFocusableContentForNestedInteractiveEvaluate; diff --git a/lib/checks/keyboard/no-focusable-content-for-nested-interactive.json b/lib/checks/keyboard/no-focusable-content-for-nested-interactive.json new file mode 100644 index 0000000000..bbd0d74506 --- /dev/null +++ b/lib/checks/keyboard/no-focusable-content-for-nested-interactive.json @@ -0,0 +1,12 @@ +{ + "id": "no-focusable-content-for-nested-interactive", + "evaluate": "no-focusable-content-for-nested-interactive-evaluate", + "metadata": { + "impact": "serious", + "messages": { + "pass": "Element does not have focusable descendants", + "fail": "Element has focusable descendants", + "incomplete": "Could not determine if element has descendants" + } + } +} diff --git a/lib/core/base/metadata-function-map.js b/lib/core/base/metadata-function-map.js index a8d8b169cb..b7dbef8c15 100644 --- a/lib/core/base/metadata-function-map.js +++ b/lib/core/base/metadata-function-map.js @@ -96,7 +96,9 @@ import focusableModalOpenEvaluate from '../../checks/keyboard/focusable-modal-op import focusableNoNameEvaluate from '../../checks/keyboard/focusable-no-name-evaluate'; import focusableNotTabbableEvaluate from '../../checks/keyboard/focusable-not-tabbable-evaluate'; import landmarkIsTopLevelEvaluate from '../../checks/keyboard/landmark-is-top-level-evaluate'; -import noFocusableContentEvaluate from '../../checks/keyboard/no-focusable-content-evaluate'; +import noFocusableContentForFrameEvaluate from '../../checks/keyboard/no-focusable-content-for-frame-evaluate'; +import noFocusableContentForAriaTextEvaluate from '../../checks/keyboard/no-focusable-content-for-aria-text-evaluate'; +import noFocusableContentForNestedInteractiveEvaluate from '../../checks/keyboard/no-focusable-content-for-nested-interactive-evaluate'; import tabindexEvaluate from '../../checks/keyboard/tabindex-evaluate'; // label @@ -273,7 +275,9 @@ const metadataFunctionMap = { 'focusable-no-name-evaluate': focusableNoNameEvaluate, 'focusable-not-tabbable-evaluate': focusableNotTabbableEvaluate, 'landmark-is-top-level-evaluate': landmarkIsTopLevelEvaluate, - 'no-focusable-content-evaluate': noFocusableContentEvaluate, + 'no-focusable-content-for-frame-evaluate': noFocusableContentForFrameEvaluate, + 'no-focusable-content-for-aria-text-evaluate': noFocusableContentForAriaTextEvaluate, + 'no-focusable-content-for-nested-interactive-evaluate': noFocusableContentForNestedInteractiveEvaluate, 'tabindex-evaluate': tabindexEvaluate, // label diff --git a/lib/rules/aria-text.json b/lib/rules/aria-text.json index aa284a5867..aa93b2fa9c 100644 --- a/lib/rules/aria-text.json +++ b/lib/rules/aria-text.json @@ -7,6 +7,6 @@ "help": "\"role=text\" should have no focusable descendants" }, "all": [], - "any": ["no-focusable-content"], + "any": ["no-focusable-content-for-aria-text"], "none": [] } diff --git a/lib/rules/frame-focusable-content.json b/lib/rules/frame-focusable-content.json index e89ab62059..6751571a2e 100644 --- a/lib/rules/frame-focusable-content.json +++ b/lib/rules/frame-focusable-content.json @@ -8,6 +8,6 @@ "help": "Frames with focusable content must not have tabindex=-1" }, "all": [], - "any": ["frame-focusable-content"], + "any": ["no-focusable-content-for-frame"], "none": [] } diff --git a/lib/rules/nested-interactive.json b/lib/rules/nested-interactive.json index 5293a7794f..aef918b515 100644 --- a/lib/rules/nested-interactive.json +++ b/lib/rules/nested-interactive.json @@ -8,6 +8,6 @@ "help": "Interactive controls must not be nested" }, "all": [], - "any": ["no-focusable-content"], + "any": ["no-focusable-content-for-nested-interactive"], "none": [] } diff --git a/test/checks/keyboard/no-focusable-content.js b/test/checks/keyboard/no-focusable-content-for-aria-text.js similarity index 65% rename from test/checks/keyboard/no-focusable-content.js rename to test/checks/keyboard/no-focusable-content-for-aria-text.js index 1e1a3a8474..48c9395729 100644 --- a/test/checks/keyboard/no-focusable-content.js +++ b/test/checks/keyboard/no-focusable-content-for-aria-text.js @@ -1,8 +1,8 @@ -describe('no-focusable-content tests', function() { +describe('no-focusable-content-for-aria-text tests', function() { var fixture = document.querySelector('#fixture'); var queryFixture = axe.testUtils.queryFixture; - var noFocusableContent = axe.testUtils.getCheckEvaluate( - 'no-focusable-content' + var noFocusableContentForAriaText = axe.testUtils.getCheckEvaluate( + 'no-focusable-content-for-aria-text' ); afterEach(function() { @@ -11,30 +11,31 @@ describe('no-focusable-content tests', function() { it('should return true if element has no focusable content', function() { var vNode = queryFixture(''); - assert.isTrue(noFocusableContent(null, null, vNode)); + assert.isTrue(noFocusableContentForAriaText(null, null, vNode)); }); it('should return true if element is empty', function() { var vNode = queryFixture(''); - assert.isTrue(noFocusableContent(null, null, vNode)); + assert.isTrue(noFocusableContentForAriaText(null, null, vNode)); }); it('should return true if element only has text content', function() { var vNode = queryFixture(''); - assert.isTrue(noFocusableContent(null, null, vNode)); + assert.isTrue(noFocusableContentForAriaText(null, null, vNode)); }); it('should return false if element has focusable content', function() { var vNode = queryFixture( '' ); - assert.isFalse(noFocusableContent(null, null, vNode)); + assert.isFalse(noFocusableContentForAriaText(null, null, vNode)); }); it('should return false if element has natively focusable content', function() { var vNode = queryFixture( '' ); - assert.isFalse(noFocusableContent(null, null, vNode)); + assert.isFalse(noFocusableContentForAriaText(null, null, vNode)); }); + }); diff --git a/test/checks/keyboard/no-focusable-content-for-nested-interactive.js b/test/checks/keyboard/no-focusable-content-for-nested-interactive.js new file mode 100644 index 0000000000..4c4553e9bf --- /dev/null +++ b/test/checks/keyboard/no-focusable-content-for-nested-interactive.js @@ -0,0 +1,41 @@ +describe('no-focusable-content-for-nested-interactive tests', function() { + var fixture = document.querySelector('#fixture'); + var queryFixture = axe.testUtils.queryFixture; + var noFocusableContentForNestedInteractive = axe.testUtils.getCheckEvaluate( + 'no-focusable-content-for-nested-interactive' + ); + + afterEach(function() { + fixture.innerHTML = ''; + }); + + it('should return true if element has no focusable content', function() { + var vNode = queryFixture(''); + assert.isTrue(noFocusableContentForNestedInteractive(null, null, vNode)); + }); + + it('should return true if element is empty', function() { + var vNode = queryFixture(''); + assert.isTrue(noFocusableContentForNestedInteractive(null, null, vNode)); + }); + + it('should return true if element only has text content', function() { + var vNode = queryFixture(''); + assert.isTrue(noFocusableContentForNestedInteractive(null, null, vNode)); + }); + + it('should return false if element has focusable content', function() { + var vNode = queryFixture( + '' + ); + assert.isFalse(noFocusableContentForNestedInteractive(null, null, vNode)); + }); + + it('should return false if element has natively focusable content', function() { + var vNode = queryFixture( + '' + ); + assert.isFalse(noFocusableContentForNestedInteractive(null, null, vNode)); + }); + +}); From 373d691f1ec7086909dbdf62351491093699c52b Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Wed, 6 Oct 2021 20:37:05 -0400 Subject: [PATCH 10/28] fix(rule): add custom message for nested-interactive. aria-hidden and negative tabindex will trigger messageKey. --- ...content-for-nested-interactive-evaluate.js | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js b/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js index c68fb171fa..4af16f2417 100644 --- a/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js @@ -1,32 +1,49 @@ import isFocusable from '../../commons/dom/is-focusable'; +import { tokenList } from '../../core/utils'; -function focusableDescendants(vNode) { - if (isFocusable(vNode)) { - return true; - } - +function getFocusableDescendants(vNode) { if (!vNode.children) { if (vNode.props.nodeType === 1) { throw new Error('Cannot determine children'); } - return false; + return []; } - return vNode.children.some(child => { - return focusableDescendants(child); + let retVal = []; + vNode.children.forEach(child => { + if(isFocusable(child)) { + retVal.push(child); + } else { + getFocusableDescendants(child).forEach(descendantOfChild => retVal.push(descendantOfChild)); + } }); + return retVal; +} + +function usesUnreliableHidingStrategy(vNode) { + let tabIndex = parseInt(vNode.attr('tabindex'), 10); + return !isNaN(tabIndex) && tabIndex < 0 && vNode.attr('aria-hidden') == 'true'; } function noFocusableContentForNestedInteractiveEvaluate(node, options, virtualNode) { if (!virtualNode.children) { return undefined; } - try { - return !virtualNode.children.some(child => { - return focusableDescendants(child); - }); + let focusableDescendants = getFocusableDescendants(virtualNode); + if(focusableDescendants.length > 0) { + let focusableDescendantsThatUseUnreliableHidingStrategy = focusableDescendants.filter( + descendant => usesUnreliableHidingStrategy(descendant)); + if(focusableDescendantsThatUseUnreliableHidingStrategy.length > 0) { + let ids = focusableDescendantsThatUseUnreliableHidingStrategy.map(node => node.attr('id')); + let n = focusableDescendantsThatUseUnreliableHidingStrategy.length; + let msg = `Using aria-hidden and negative tabindex is not a reliable way of hiding interactive elements. ` + +`Element ids: [${ids.map(id => '"'+id+'"')}].`; + this.data({messageKey: 'info', values: msg}); + } + } + return focusableDescendants.length == 0; } catch (e) { return undefined; } From deea093bd227db7edc3fc17825ec9cbdd7d0eac0 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Thu, 7 Oct 2021 20:35:38 -0400 Subject: [PATCH 11/28] style(rule): fix lint errors Errors were in parent commit. --- ...content-for-nested-interactive-evaluate.js | 20 +++++++++---------- 1 file changed, 9 insertions(+), 11 deletions(-) diff --git a/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js b/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js index 4af16f2417..4cc5c7a2fa 100644 --- a/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js @@ -1,5 +1,4 @@ import isFocusable from '../../commons/dom/is-focusable'; -import { tokenList } from '../../core/utils'; function getFocusableDescendants(vNode) { if (!vNode.children) { @@ -10,7 +9,7 @@ function getFocusableDescendants(vNode) { return []; } - let retVal = []; + const retVal = []; vNode.children.forEach(child => { if(isFocusable(child)) { retVal.push(child); @@ -22,8 +21,8 @@ function getFocusableDescendants(vNode) { } function usesUnreliableHidingStrategy(vNode) { - let tabIndex = parseInt(vNode.attr('tabindex'), 10); - return !isNaN(tabIndex) && tabIndex < 0 && vNode.attr('aria-hidden') == 'true'; + const tabIndex = parseInt(vNode.attr('tabindex'), 10); + return !isNaN(tabIndex) && tabIndex < 0 && vNode.attr('aria-hidden') === 'true'; } function noFocusableContentForNestedInteractiveEvaluate(node, options, virtualNode) { @@ -31,19 +30,18 @@ function noFocusableContentForNestedInteractiveEvaluate(node, options, virtualNo return undefined; } try { - let focusableDescendants = getFocusableDescendants(virtualNode); + const focusableDescendants = getFocusableDescendants(virtualNode); if(focusableDescendants.length > 0) { - let focusableDescendantsThatUseUnreliableHidingStrategy = focusableDescendants.filter( + const focusableDescendantsThatUseUnreliableHidingStrategy = focusableDescendants.filter( descendant => usesUnreliableHidingStrategy(descendant)); if(focusableDescendantsThatUseUnreliableHidingStrategy.length > 0) { - let ids = focusableDescendantsThatUseUnreliableHidingStrategy.map(node => node.attr('id')); - let n = focusableDescendantsThatUseUnreliableHidingStrategy.length; - let msg = `Using aria-hidden and negative tabindex is not a reliable way of hiding interactive elements. ` - +`Element ids: [${ids.map(id => '"'+id+'"')}].`; + const ids = focusableDescendantsThatUseUnreliableHidingStrategy.map(node => node.attr('id')); + const msg = `Using aria-hidden and negative tabindex is not a reliable way of hiding interactive elements. ` + +`Element id(s): [${ids.map(id => '"'+id+'"')}].`; this.data({messageKey: 'info', values: msg}); } } - return focusableDescendants.length == 0; + return focusableDescendants.length === 0; } catch (e) { return undefined; } From deac42b2736bb8b90a1c5da3475ea5db39cf8025 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Thu, 7 Oct 2021 21:18:00 -0400 Subject: [PATCH 12/28] fix(no-focusable-content-for-frame): fix locale files Was broken by recent rename of this check. --- locales/fr.json | 2 +- locales/ja.json | 2 +- locales/ko.json | 2 +- locales/pl.json | 2 +- locales/pt_BR.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index a1cba7785d..1e3a831fe5 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -604,7 +604,7 @@ "pass": "Aucun élément focalisable contenu dans l’élément", "fail": "Le contenu focalisable devrait se voir assigné un tabindex='-1' ou être retiré du DOM" }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "L’élément n’a pas de descendants focalisables", "fail": "L’élément a des descendants focalisables", "incomplete": "Impossible de déterminer si l’élément a des descendants" diff --git a/locales/ja.json b/locales/ja.json index d9b354a254..4451bd2a88 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -590,7 +590,7 @@ "pass": "要素内にフォーカス不可能な要素は含まれていません", "fail": "フォーカス可能なコンテンツは tabindex='-1' を指定するか、DOMから削除するべきです" }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "要素の子孫にフォーカス可能なものはありません", "fail": "要素の子孫にフォーカス可能なものがあります", "incomplete": "要素に子孫があるか判定できませんでした" diff --git a/locales/ko.json b/locales/ko.json index fe18dbf9ae..7b0fbd825c 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -601,7 +601,7 @@ "pass": "엘리먼트 안에 초점을 얻을 수 있는(focusable) 엘리먼트가 없습니다.", "fail": "초점을 얻을 수 있는(focusable) 콘텐츠는 tabindex='-1'을 가지거나 DOM에서 제거되어야 합니다." }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 없습니다.", "fail": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 있습니다.", "incomplete": "엘리먼트에 후손 항목이 있는지 확인할 수 없습니다." diff --git a/locales/pl.json b/locales/pl.json index be299186d2..45a94d4a4c 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -590,7 +590,7 @@ "pass": "Nie ma elementów przyjmujących fokus wewnątrz elementu.", "fail": "Treść przyjmująca fokus powinna mieć tabindex=-1 lub być usunięta z DOM." }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "Element nie ma potomków przyjmujących fokus", "fail": "Element ma elementy potomne przyjmujące fokus", "incomplete": "Nie można ustalić, czy element ma elementy potomne" diff --git a/locales/pt_BR.json b/locales/pt_BR.json index b5441b9c04..3ccfbbf568 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -593,7 +593,7 @@ "pass": "Nenhum elemento focalizável contido no elemento", "fail": "Conteúdo focalizável deve ter tabindex='-1' ou ser removido do DOM" }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "O elemento não tem descendentes focalizáveis", "fail": "O elemento tem descendentes focalizáveis", "incomplete": "Não foi possível determinar se o elemento tem descendentes" From 1a980bc3522e399e08247315f8c4ebf7361f1519 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Sat, 9 Oct 2021 09:10:25 -0400 Subject: [PATCH 13/28] refactor(check): undo recent check rename Rename check "no-focusable-content-for-frame" back to "frame-focusable-content". --- ...or-frame-evaluate.js => frame-focusable-content-evaluate.js} | 0 ...able-content-for-frame.json => frame-focusable-content.json} | 2 +- lib/core/base/metadata-function-map.js | 2 +- lib/rules/frame-focusable-content.json | 2 +- locales/fr.json | 2 +- locales/ja.json | 2 +- locales/ko.json | 2 +- locales/pl.json | 2 +- locales/pt_BR.json | 2 +- 9 files changed, 8 insertions(+), 8 deletions(-) rename lib/checks/keyboard/{no-focusable-content-for-frame-evaluate.js => frame-focusable-content-evaluate.js} (100%) rename lib/checks/keyboard/{no-focusable-content-for-frame.json => frame-focusable-content.json} (88%) diff --git a/lib/checks/keyboard/no-focusable-content-for-frame-evaluate.js b/lib/checks/keyboard/frame-focusable-content-evaluate.js similarity index 100% rename from lib/checks/keyboard/no-focusable-content-for-frame-evaluate.js rename to lib/checks/keyboard/frame-focusable-content-evaluate.js diff --git a/lib/checks/keyboard/no-focusable-content-for-frame.json b/lib/checks/keyboard/frame-focusable-content.json similarity index 88% rename from lib/checks/keyboard/no-focusable-content-for-frame.json rename to lib/checks/keyboard/frame-focusable-content.json index 8f5e73c587..274ffac76e 100644 --- a/lib/checks/keyboard/no-focusable-content-for-frame.json +++ b/lib/checks/keyboard/frame-focusable-content.json @@ -1,5 +1,5 @@ { - "id": "no-focusable-content-for-frame", + "id": "frame-focusable-content", "evaluate": "no-focusable-content-for-frame-evaluate", "metadata": { "impact": "serious", diff --git a/lib/core/base/metadata-function-map.js b/lib/core/base/metadata-function-map.js index b7dbef8c15..fcabf06a73 100644 --- a/lib/core/base/metadata-function-map.js +++ b/lib/core/base/metadata-function-map.js @@ -96,7 +96,7 @@ import focusableModalOpenEvaluate from '../../checks/keyboard/focusable-modal-op import focusableNoNameEvaluate from '../../checks/keyboard/focusable-no-name-evaluate'; import focusableNotTabbableEvaluate from '../../checks/keyboard/focusable-not-tabbable-evaluate'; import landmarkIsTopLevelEvaluate from '../../checks/keyboard/landmark-is-top-level-evaluate'; -import noFocusableContentForFrameEvaluate from '../../checks/keyboard/no-focusable-content-for-frame-evaluate'; +import noFocusableContentForFrameEvaluate from '../../checks/keyboard/frame-focusable-content-evaluate'; import noFocusableContentForAriaTextEvaluate from '../../checks/keyboard/no-focusable-content-for-aria-text-evaluate'; import noFocusableContentForNestedInteractiveEvaluate from '../../checks/keyboard/no-focusable-content-for-nested-interactive-evaluate'; import tabindexEvaluate from '../../checks/keyboard/tabindex-evaluate'; diff --git a/lib/rules/frame-focusable-content.json b/lib/rules/frame-focusable-content.json index 6751571a2e..e89ab62059 100644 --- a/lib/rules/frame-focusable-content.json +++ b/lib/rules/frame-focusable-content.json @@ -8,6 +8,6 @@ "help": "Frames with focusable content must not have tabindex=-1" }, "all": [], - "any": ["no-focusable-content-for-frame"], + "any": ["frame-focusable-content"], "none": [] } diff --git a/locales/fr.json b/locales/fr.json index 1e3a831fe5..a1cba7785d 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -604,7 +604,7 @@ "pass": "Aucun élément focalisable contenu dans l’élément", "fail": "Le contenu focalisable devrait se voir assigné un tabindex='-1' ou être retiré du DOM" }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "L’élément n’a pas de descendants focalisables", "fail": "L’élément a des descendants focalisables", "incomplete": "Impossible de déterminer si l’élément a des descendants" diff --git a/locales/ja.json b/locales/ja.json index 4451bd2a88..d9b354a254 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -590,7 +590,7 @@ "pass": "要素内にフォーカス不可能な要素は含まれていません", "fail": "フォーカス可能なコンテンツは tabindex='-1' を指定するか、DOMから削除するべきです" }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "要素の子孫にフォーカス可能なものはありません", "fail": "要素の子孫にフォーカス可能なものがあります", "incomplete": "要素に子孫があるか判定できませんでした" diff --git a/locales/ko.json b/locales/ko.json index 7b0fbd825c..fe18dbf9ae 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -601,7 +601,7 @@ "pass": "엘리먼트 안에 초점을 얻을 수 있는(focusable) 엘리먼트가 없습니다.", "fail": "초점을 얻을 수 있는(focusable) 콘텐츠는 tabindex='-1'을 가지거나 DOM에서 제거되어야 합니다." }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 없습니다.", "fail": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 있습니다.", "incomplete": "엘리먼트에 후손 항목이 있는지 확인할 수 없습니다." diff --git a/locales/pl.json b/locales/pl.json index 45a94d4a4c..be299186d2 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -590,7 +590,7 @@ "pass": "Nie ma elementów przyjmujących fokus wewnątrz elementu.", "fail": "Treść przyjmująca fokus powinna mieć tabindex=-1 lub być usunięta z DOM." }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "Element nie ma potomków przyjmujących fokus", "fail": "Element ma elementy potomne przyjmujące fokus", "incomplete": "Nie można ustalić, czy element ma elementy potomne" diff --git a/locales/pt_BR.json b/locales/pt_BR.json index 3ccfbbf568..b5441b9c04 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -593,7 +593,7 @@ "pass": "Nenhum elemento focalizável contido no elemento", "fail": "Conteúdo focalizável deve ter tabindex='-1' ou ser removido do DOM" }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "O elemento não tem descendentes focalizáveis", "fail": "O elemento tem descendentes focalizáveis", "incomplete": "Não foi possível determinar se o elemento tem descendentes" From c141a585934bc983f2197efe38dfa7ac463a3191 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Sat, 9 Oct 2021 09:29:38 -0400 Subject: [PATCH 14/28] refactor(check): undo recent split of checks Recombine checks "no-focusable-content-for-aria-text" and "no-focusable-content-for-nested-interactive" back into "no-focusable-content". --- ...te.js => no-focusable-content-evaluate.js} | 4 +- ...ocusable-content-for-aria-text-evaluate.js | 35 ---------------- ...usable-content-for-nested-interactive.json | 12 ------ ...ia-text.json => no-focusable-content.json} | 4 +- lib/core/base/metadata-function-map.js | 6 +-- lib/rules/aria-text.json | 2 +- lib/rules/nested-interactive.json | 2 +- ...ocusable-content-for-nested-interactive.js | 41 ------------------- ...r-aria-text.js => no-focusable-content.js} | 16 ++++---- 9 files changed, 16 insertions(+), 106 deletions(-) rename lib/checks/keyboard/{no-focusable-content-for-nested-interactive-evaluate.js => no-focusable-content-evaluate.js} (91%) delete mode 100644 lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js delete mode 100644 lib/checks/keyboard/no-focusable-content-for-nested-interactive.json rename lib/checks/keyboard/{no-focusable-content-for-aria-text.json => no-focusable-content.json} (70%) delete mode 100644 test/checks/keyboard/no-focusable-content-for-nested-interactive.js rename test/checks/keyboard/{no-focusable-content-for-aria-text.js => no-focusable-content.js} (65%) diff --git a/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js b/lib/checks/keyboard/no-focusable-content-evaluate.js similarity index 91% rename from lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js rename to lib/checks/keyboard/no-focusable-content-evaluate.js index 4cc5c7a2fa..0d7eeb6b65 100644 --- a/lib/checks/keyboard/no-focusable-content-for-nested-interactive-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-evaluate.js @@ -25,7 +25,7 @@ function usesUnreliableHidingStrategy(vNode) { return !isNaN(tabIndex) && tabIndex < 0 && vNode.attr('aria-hidden') === 'true'; } -function noFocusableContentForNestedInteractiveEvaluate(node, options, virtualNode) { +function noFocusableContentEvaluate(node, options, virtualNode) { if (!virtualNode.children) { return undefined; } @@ -47,4 +47,4 @@ function noFocusableContentForNestedInteractiveEvaluate(node, options, virtualNo } } -export default noFocusableContentForNestedInteractiveEvaluate; +export default noFocusableContentEvaluate; diff --git a/lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js b/lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js deleted file mode 100644 index fc2ef483bd..0000000000 --- a/lib/checks/keyboard/no-focusable-content-for-aria-text-evaluate.js +++ /dev/null @@ -1,35 +0,0 @@ -import isFocusable from '../../commons/dom/is-focusable'; - -function focusableDescendants(vNode) { - if (isFocusable(vNode)) { - return true; - } - - if (!vNode.children) { - if (vNode.props.nodeType === 1) { - throw new Error('Cannot determine children'); - } - - return false; - } - - return vNode.children.some(child => { - return focusableDescendants(child); - }); -} - -function noFocusableContentForAriaTextEvaluate(node, options, virtualNode) { - if (!virtualNode.children) { - return undefined; - } - - try { - return !virtualNode.children.some(child => { - return focusableDescendants(child); - }); - } catch (e) { - return undefined; - } -} - -export default noFocusableContentForAriaTextEvaluate; diff --git a/lib/checks/keyboard/no-focusable-content-for-nested-interactive.json b/lib/checks/keyboard/no-focusable-content-for-nested-interactive.json deleted file mode 100644 index bbd0d74506..0000000000 --- a/lib/checks/keyboard/no-focusable-content-for-nested-interactive.json +++ /dev/null @@ -1,12 +0,0 @@ -{ - "id": "no-focusable-content-for-nested-interactive", - "evaluate": "no-focusable-content-for-nested-interactive-evaluate", - "metadata": { - "impact": "serious", - "messages": { - "pass": "Element does not have focusable descendants", - "fail": "Element has focusable descendants", - "incomplete": "Could not determine if element has descendants" - } - } -} diff --git a/lib/checks/keyboard/no-focusable-content-for-aria-text.json b/lib/checks/keyboard/no-focusable-content.json similarity index 70% rename from lib/checks/keyboard/no-focusable-content-for-aria-text.json rename to lib/checks/keyboard/no-focusable-content.json index 4d89a75a63..a67554e6a8 100644 --- a/lib/checks/keyboard/no-focusable-content-for-aria-text.json +++ b/lib/checks/keyboard/no-focusable-content.json @@ -1,6 +1,6 @@ { - "id": "no-focusable-content-for-aria-text", - "evaluate": "no-focusable-content-for-aria-text-evaluate", + "id": "no-focusable-content", + "evaluate": "no-focusable-content-evaluate", "metadata": { "impact": "serious", "messages": { diff --git a/lib/core/base/metadata-function-map.js b/lib/core/base/metadata-function-map.js index fcabf06a73..9728debe69 100644 --- a/lib/core/base/metadata-function-map.js +++ b/lib/core/base/metadata-function-map.js @@ -97,8 +97,7 @@ import focusableNoNameEvaluate from '../../checks/keyboard/focusable-no-name-eva import focusableNotTabbableEvaluate from '../../checks/keyboard/focusable-not-tabbable-evaluate'; import landmarkIsTopLevelEvaluate from '../../checks/keyboard/landmark-is-top-level-evaluate'; import noFocusableContentForFrameEvaluate from '../../checks/keyboard/frame-focusable-content-evaluate'; -import noFocusableContentForAriaTextEvaluate from '../../checks/keyboard/no-focusable-content-for-aria-text-evaluate'; -import noFocusableContentForNestedInteractiveEvaluate from '../../checks/keyboard/no-focusable-content-for-nested-interactive-evaluate'; +import noFocusableContentEvaluate from '../../checks/keyboard/no-focusable-content-evaluate'; import tabindexEvaluate from '../../checks/keyboard/tabindex-evaluate'; // label @@ -276,8 +275,7 @@ const metadataFunctionMap = { 'focusable-not-tabbable-evaluate': focusableNotTabbableEvaluate, 'landmark-is-top-level-evaluate': landmarkIsTopLevelEvaluate, 'no-focusable-content-for-frame-evaluate': noFocusableContentForFrameEvaluate, - 'no-focusable-content-for-aria-text-evaluate': noFocusableContentForAriaTextEvaluate, - 'no-focusable-content-for-nested-interactive-evaluate': noFocusableContentForNestedInteractiveEvaluate, + 'no-focusable-content-evaluate': noFocusableContentEvaluate, 'tabindex-evaluate': tabindexEvaluate, // label diff --git a/lib/rules/aria-text.json b/lib/rules/aria-text.json index aa93b2fa9c..aa284a5867 100644 --- a/lib/rules/aria-text.json +++ b/lib/rules/aria-text.json @@ -7,6 +7,6 @@ "help": "\"role=text\" should have no focusable descendants" }, "all": [], - "any": ["no-focusable-content-for-aria-text"], + "any": ["no-focusable-content"], "none": [] } diff --git a/lib/rules/nested-interactive.json b/lib/rules/nested-interactive.json index aef918b515..5293a7794f 100644 --- a/lib/rules/nested-interactive.json +++ b/lib/rules/nested-interactive.json @@ -8,6 +8,6 @@ "help": "Interactive controls must not be nested" }, "all": [], - "any": ["no-focusable-content-for-nested-interactive"], + "any": ["no-focusable-content"], "none": [] } diff --git a/test/checks/keyboard/no-focusable-content-for-nested-interactive.js b/test/checks/keyboard/no-focusable-content-for-nested-interactive.js deleted file mode 100644 index 4c4553e9bf..0000000000 --- a/test/checks/keyboard/no-focusable-content-for-nested-interactive.js +++ /dev/null @@ -1,41 +0,0 @@ -describe('no-focusable-content-for-nested-interactive tests', function() { - var fixture = document.querySelector('#fixture'); - var queryFixture = axe.testUtils.queryFixture; - var noFocusableContentForNestedInteractive = axe.testUtils.getCheckEvaluate( - 'no-focusable-content-for-nested-interactive' - ); - - afterEach(function() { - fixture.innerHTML = ''; - }); - - it('should return true if element has no focusable content', function() { - var vNode = queryFixture(''); - assert.isTrue(noFocusableContentForNestedInteractive(null, null, vNode)); - }); - - it('should return true if element is empty', function() { - var vNode = queryFixture(''); - assert.isTrue(noFocusableContentForNestedInteractive(null, null, vNode)); - }); - - it('should return true if element only has text content', function() { - var vNode = queryFixture(''); - assert.isTrue(noFocusableContentForNestedInteractive(null, null, vNode)); - }); - - it('should return false if element has focusable content', function() { - var vNode = queryFixture( - '' - ); - assert.isFalse(noFocusableContentForNestedInteractive(null, null, vNode)); - }); - - it('should return false if element has natively focusable content', function() { - var vNode = queryFixture( - '' - ); - assert.isFalse(noFocusableContentForNestedInteractive(null, null, vNode)); - }); - -}); diff --git a/test/checks/keyboard/no-focusable-content-for-aria-text.js b/test/checks/keyboard/no-focusable-content.js similarity index 65% rename from test/checks/keyboard/no-focusable-content-for-aria-text.js rename to test/checks/keyboard/no-focusable-content.js index 48c9395729..761bbb547d 100644 --- a/test/checks/keyboard/no-focusable-content-for-aria-text.js +++ b/test/checks/keyboard/no-focusable-content.js @@ -1,8 +1,8 @@ -describe('no-focusable-content-for-aria-text tests', function() { +describe('no-focusable-content tests', function() { var fixture = document.querySelector('#fixture'); var queryFixture = axe.testUtils.queryFixture; - var noFocusableContentForAriaText = axe.testUtils.getCheckEvaluate( - 'no-focusable-content-for-aria-text' + var noFocusableContent = axe.testUtils.getCheckEvaluate( + 'no-focusable-content' ); afterEach(function() { @@ -11,31 +11,31 @@ describe('no-focusable-content-for-aria-text tests', function() { it('should return true if element has no focusable content', function() { var vNode = queryFixture(''); - assert.isTrue(noFocusableContentForAriaText(null, null, vNode)); + assert.isTrue(noFocusableContent(null, null, vNode)); }); it('should return true if element is empty', function() { var vNode = queryFixture(''); - assert.isTrue(noFocusableContentForAriaText(null, null, vNode)); + assert.isTrue(noFocusableContent(null, null, vNode)); }); it('should return true if element only has text content', function() { var vNode = queryFixture(''); - assert.isTrue(noFocusableContentForAriaText(null, null, vNode)); + assert.isTrue(noFocusableContent(null, null, vNode)); }); it('should return false if element has focusable content', function() { var vNode = queryFixture( '' ); - assert.isFalse(noFocusableContentForAriaText(null, null, vNode)); + assert.isFalse(noFocusableContent(null, null, vNode)); }); it('should return false if element has natively focusable content', function() { var vNode = queryFixture( '' ); - assert.isFalse(noFocusableContentForAriaText(null, null, vNode)); + assert.isFalse(noFocusableContent(null, null, vNode)); }); }); From 9eed89006a7db96e5a430ae5fe450a5910b02e86 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Sat, 9 Oct 2021 09:37:22 -0400 Subject: [PATCH 15/28] refactor(check): rename local variable --- lib/checks/keyboard/no-focusable-content-evaluate.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/lib/checks/keyboard/no-focusable-content-evaluate.js b/lib/checks/keyboard/no-focusable-content-evaluate.js index 0d7eeb6b65..2772e05d0c 100644 --- a/lib/checks/keyboard/no-focusable-content-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-evaluate.js @@ -32,10 +32,9 @@ function noFocusableContentEvaluate(node, options, virtualNode) { try { const focusableDescendants = getFocusableDescendants(virtualNode); if(focusableDescendants.length > 0) { - const focusableDescendantsThatUseUnreliableHidingStrategy = focusableDescendants.filter( - descendant => usesUnreliableHidingStrategy(descendant)); - if(focusableDescendantsThatUseUnreliableHidingStrategy.length > 0) { - const ids = focusableDescendantsThatUseUnreliableHidingStrategy.map(node => node.attr('id')); + const unreliableElems = focusableDescendants.filter(descendant => usesUnreliableHidingStrategy(descendant)); + if(unreliableElems.length > 0) { + const ids = unreliableElems.map(node => node.attr('id')); const msg = `Using aria-hidden and negative tabindex is not a reliable way of hiding interactive elements. ` +`Element id(s): [${ids.map(id => '"'+id+'"')}].`; this.data({messageKey: 'info', values: msg}); From 6bd74ea59dd3d131a415626e024d30fbe637ad6e Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Sat, 9 Oct 2021 09:39:15 -0400 Subject: [PATCH 16/28] fix(rule): make no-focusable-content not consult aria-hidden no-focusable content now consults only tabindex (for the 'not a reliable way of hiding interactive elements' messageKey check) --- lib/checks/keyboard/no-focusable-content-evaluate.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/checks/keyboard/no-focusable-content-evaluate.js b/lib/checks/keyboard/no-focusable-content-evaluate.js index 2772e05d0c..65d02d044f 100644 --- a/lib/checks/keyboard/no-focusable-content-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-evaluate.js @@ -22,7 +22,7 @@ function getFocusableDescendants(vNode) { function usesUnreliableHidingStrategy(vNode) { const tabIndex = parseInt(vNode.attr('tabindex'), 10); - return !isNaN(tabIndex) && tabIndex < 0 && vNode.attr('aria-hidden') === 'true'; + return !isNaN(tabIndex) && tabIndex < 0; } function noFocusableContentEvaluate(node, options, virtualNode) { @@ -35,7 +35,7 @@ function noFocusableContentEvaluate(node, options, virtualNode) { const unreliableElems = focusableDescendants.filter(descendant => usesUnreliableHidingStrategy(descendant)); if(unreliableElems.length > 0) { const ids = unreliableElems.map(node => node.attr('id')); - const msg = `Using aria-hidden and negative tabindex is not a reliable way of hiding interactive elements. ` + const msg = `Using negative tabindex is not a reliable way of hiding interactive elements. ` +`Element id(s): [${ids.map(id => '"'+id+'"')}].`; this.data({messageKey: 'info', values: msg}); } From ac048bea6b7d8b4b1c6799a16ebc75ca55ff2c45 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Sat, 9 Oct 2021 10:04:23 -0400 Subject: [PATCH 17/28] fix(checks/keyboard): make no-focusable-content use messageKey the right way --- lib/checks/keyboard/no-focusable-content-evaluate.js | 10 ++++------ lib/checks/keyboard/no-focusable-content.json | 5 ++++- 2 files changed, 8 insertions(+), 7 deletions(-) diff --git a/lib/checks/keyboard/no-focusable-content-evaluate.js b/lib/checks/keyboard/no-focusable-content-evaluate.js index 65d02d044f..043dbfdf9f 100644 --- a/lib/checks/keyboard/no-focusable-content-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-evaluate.js @@ -32,12 +32,10 @@ function noFocusableContentEvaluate(node, options, virtualNode) { try { const focusableDescendants = getFocusableDescendants(virtualNode); if(focusableDescendants.length > 0) { - const unreliableElems = focusableDescendants.filter(descendant => usesUnreliableHidingStrategy(descendant)); - if(unreliableElems.length > 0) { - const ids = unreliableElems.map(node => node.attr('id')); - const msg = `Using negative tabindex is not a reliable way of hiding interactive elements. ` - +`Element id(s): [${ids.map(id => '"'+id+'"')}].`; - this.data({messageKey: 'info', values: msg}); + const notHiddenElements = focusableDescendants.filter(descendant => usesUnreliableHidingStrategy(descendant)); + if(notHiddenElements.length > 0) { + this.data({ messageKey: 'notHidden' }); + this.relatedNodes(notHiddenElements); } } return focusableDescendants.length === 0; diff --git a/lib/checks/keyboard/no-focusable-content.json b/lib/checks/keyboard/no-focusable-content.json index a67554e6a8..35c40fc77b 100644 --- a/lib/checks/keyboard/no-focusable-content.json +++ b/lib/checks/keyboard/no-focusable-content.json @@ -5,7 +5,10 @@ "impact": "serious", "messages": { "pass": "Element does not have focusable descendants", - "fail": "Element has focusable descendants", + "fail": { + "default": "Element has focusable descendants", + "notHidden": "Using negative tabindex is not a reliable way of hiding interactive elements" + }, "incomplete": "Could not determine if element has descendants" } } From 540eb794f57b78d1d1a0eeb89c466a58869df3c3 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Wed, 13 Oct 2021 20:27:28 -0400 Subject: [PATCH 18/28] refactor(check): misc. renaming and refactoring --- lib/checks/keyboard/frame-focusable-content-evaluate.js | 4 ++-- lib/checks/keyboard/frame-focusable-content.json | 2 +- lib/checks/keyboard/no-focusable-content-evaluate.js | 4 ++-- lib/core/base/metadata-function-map.js | 4 ++-- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/lib/checks/keyboard/frame-focusable-content-evaluate.js b/lib/checks/keyboard/frame-focusable-content-evaluate.js index ecbc419892..0624167778 100644 --- a/lib/checks/keyboard/frame-focusable-content-evaluate.js +++ b/lib/checks/keyboard/frame-focusable-content-evaluate.js @@ -18,7 +18,7 @@ function focusableDescendants(vNode) { }); } -function noFocusableContentForFrameEvaluate(node, options, virtualNode) { +function frameFocusableContentEvaluate(node, options, virtualNode) { if (!virtualNode.children) { return undefined; } @@ -32,4 +32,4 @@ function noFocusableContentForFrameEvaluate(node, options, virtualNode) { } } -export default noFocusableContentForFrameEvaluate; +export default frameFocusableContentEvaluate; diff --git a/lib/checks/keyboard/frame-focusable-content.json b/lib/checks/keyboard/frame-focusable-content.json index 274ffac76e..6926a2ccf2 100644 --- a/lib/checks/keyboard/frame-focusable-content.json +++ b/lib/checks/keyboard/frame-focusable-content.json @@ -1,6 +1,6 @@ { "id": "frame-focusable-content", - "evaluate": "no-focusable-content-for-frame-evaluate", + "evaluate": "frame-focusable-content-evaluate", "metadata": { "impact": "serious", "messages": { diff --git a/lib/checks/keyboard/no-focusable-content-evaluate.js b/lib/checks/keyboard/no-focusable-content-evaluate.js index 043dbfdf9f..907e32ee29 100644 --- a/lib/checks/keyboard/no-focusable-content-evaluate.js +++ b/lib/checks/keyboard/no-focusable-content-evaluate.js @@ -14,7 +14,7 @@ function getFocusableDescendants(vNode) { if(isFocusable(child)) { retVal.push(child); } else { - getFocusableDescendants(child).forEach(descendantOfChild => retVal.push(descendantOfChild)); + retVal.push(...getFocusableDescendants(child)); } }); return retVal; @@ -32,7 +32,7 @@ function noFocusableContentEvaluate(node, options, virtualNode) { try { const focusableDescendants = getFocusableDescendants(virtualNode); if(focusableDescendants.length > 0) { - const notHiddenElements = focusableDescendants.filter(descendant => usesUnreliableHidingStrategy(descendant)); + const notHiddenElements = focusableDescendants.filter(usesUnreliableHidingStrategy); if(notHiddenElements.length > 0) { this.data({ messageKey: 'notHidden' }); this.relatedNodes(notHiddenElements); diff --git a/lib/core/base/metadata-function-map.js b/lib/core/base/metadata-function-map.js index 9728debe69..362d57c362 100644 --- a/lib/core/base/metadata-function-map.js +++ b/lib/core/base/metadata-function-map.js @@ -96,7 +96,7 @@ import focusableModalOpenEvaluate from '../../checks/keyboard/focusable-modal-op import focusableNoNameEvaluate from '../../checks/keyboard/focusable-no-name-evaluate'; import focusableNotTabbableEvaluate from '../../checks/keyboard/focusable-not-tabbable-evaluate'; import landmarkIsTopLevelEvaluate from '../../checks/keyboard/landmark-is-top-level-evaluate'; -import noFocusableContentForFrameEvaluate from '../../checks/keyboard/frame-focusable-content-evaluate'; +import frameFocusableContentEvaluate from '../../checks/keyboard/frame-focusable-content-evaluate'; import noFocusableContentEvaluate from '../../checks/keyboard/no-focusable-content-evaluate'; import tabindexEvaluate from '../../checks/keyboard/tabindex-evaluate'; @@ -274,7 +274,7 @@ const metadataFunctionMap = { 'focusable-no-name-evaluate': focusableNoNameEvaluate, 'focusable-not-tabbable-evaluate': focusableNotTabbableEvaluate, 'landmark-is-top-level-evaluate': landmarkIsTopLevelEvaluate, - 'no-focusable-content-for-frame-evaluate': noFocusableContentForFrameEvaluate, + 'frame-focusable-content-evaluate': frameFocusableContentEvaluate, 'no-focusable-content-evaluate': noFocusableContentEvaluate, 'tabindex-evaluate': tabindexEvaluate, From 801f6874fd3df976f0f7b691eeed88d8ea80acc6 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Fri, 22 Oct 2021 20:41:33 -0400 Subject: [PATCH 19/28] Updating description / messageKey text as per https://github.com/dequelabs/axe-core/issues/3163#issuecomment-949804464 --- doc/rule-descriptions.md | 112 +++++++++--------- lib/checks/keyboard/no-focusable-content.json | 2 +- lib/rules/nested-interactive.json | 4 +- 3 files changed, 59 insertions(+), 59 deletions(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 5a949c8cc2..0f1d6cca4a 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -11,62 +11,62 @@ ## WCAG 2.0 Level A & AA Rules -| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | -| :------------------------------------------------------------------------------------------------------------------------------- | :------------------------------------------------------------------------------------------------------------ | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------- | -| [area-alt](https://dequeuniversity.com/rules/axe/4.3/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | -| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.3/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea) | -| [aria-command-name](https://dequeuniversity.com/rules/axe/4.3/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1) | -| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | | -| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | [6cfa84](https://act-rules.github.io/rules/6cfa84) | -| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | -| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.3/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | -| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.3/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | -| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.3/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | -| [aria-required-children](https://dequeuniversity.com/rules/axe/4.3/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | [ff89c9](https://act-rules.github.io/rules/ff89c9) | -| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.3/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | [bc4a75](https://act-rules.github.io/rules/bc4a75), [ff89c9](https://act-rules.github.io/rules/ff89c9) | -| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.3/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | -| [aria-roles](https://dequeuniversity.com/rules/axe/4.3/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | | -| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | | -| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.3/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | -| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea), [c487ae](https://act-rules.github.io/rules/c487ae) | -| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | -| [audio-caption](https://dequeuniversity.com/rules/axe/4.3/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | [c3232f](https://act-rules.github.io/rules/c3232f), [e7aa44](https://act-rules.github.io/rules/e7aa44) | -| [blink](https://dequeuniversity.com/rules/axe/4.3/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | | -| [button-name](https://dequeuniversity.com/rules/axe/4.3/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1), [m6b1q3](https://act-rules.github.io/rules/m6b1q3) | -| [bypass](https://dequeuniversity.com/rules/axe/4.3/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | needs review | | -| [color-contrast](https://dequeuniversity.com/rules/axe/4.3/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | | -| [definition-list](https://dequeuniversity.com/rules/axe/4.3/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [dlitem](https://dequeuniversity.com/rules/axe/4.3/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [document-title](https://dequeuniversity.com/rules/axe/4.3/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | [2779a5](https://act-rules.github.io/rules/2779a5) | -| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | | -| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | -| [duplicate-id](https://dequeuniversity.com/rules/axe/4.3/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | | -| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.3/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | | -| [frame-focusable-content](https://dequeuniversity.com/rules/axe/4.3/frame-focusable-content?application=RuleDescription) | Ensures <frame> and <iframe> elements with focusable content do not have tabindex=-1 | Serious | cat.keyboard, wcag2a, wcag211 | failure, needs review | | -| [frame-title](https://dequeuniversity.com/rules/axe/4.3/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements have an accessible name | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | | -| [html-has-lang](https://dequeuniversity.com/rules/axe/4.3/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | [b5c3f8](https://act-rules.github.io/rules/b5c3f8) | -| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.3/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | [bf051a](https://act-rules.github.io/rules/bf051a) | -| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.3/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | [5b7ae0](https://act-rules.github.io/rules/5b7ae0) | -| [image-alt](https://dequeuniversity.com/rules/axe/4.3/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | -| [input-button-name](https://dequeuniversity.com/rules/axe/4.3/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | | -| [input-image-alt](https://dequeuniversity.com/rules/axe/4.3/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [59796f](https://act-rules.github.io/rules/59796f) | -| [label](https://dequeuniversity.com/rules/axe/4.3/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5), [307n5z](https://act-rules.github.io/rules/307n5z) | -| [link-name](https://dequeuniversity.com/rules/axe/4.3/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | -| [list](https://dequeuniversity.com/rules/axe/4.3/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [listitem](https://dequeuniversity.com/rules/axe/4.3/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [marquee](https://dequeuniversity.com/rules/axe/4.3/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | | -| [meta-refresh](https://dequeuniversity.com/rules/axe/4.3/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag221, wcag224, wcag325 | failure | | -| [nested-interactive](https://dequeuniversity.com/rules/axe/4.3/nested-interactive?application=RuleDescription) | Ensure controls are not nested as they are not announced by screen readers | Serious | cat.keyboard, wcag2a, wcag412 | failure, needs review | [307n5z](https://act-rules.github.io/rules/307n5z) | -| [object-alt](https://dequeuniversity.com/rules/axe/4.3/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | [8fc3b6](https://act-rules.github.io/rules/8fc3b6) | -| [role-img-alt](https://dequeuniversity.com/rules/axe/4.3/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | -| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.3/scrollable-region-focusable?application=RuleDescription) | Ensure elements that have scrollable content are accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | [0ssw9k](https://act-rules.github.io/rules/0ssw9k) | -| [select-name](https://dequeuniversity.com/rules/axe/4.3/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | -| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.3/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | | -| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.3/svg-img-alt?application=RuleDescription) | Ensures <svg> elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [7d6734](https://act-rules.github.io/rules/7d6734) | -| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.3/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table that uses the headers attribute refers only to other cells in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [a25f45](https://act-rules.github.io/rules/a25f45) | -| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.3/th-has-data-cells?application=RuleDescription) | Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [d0f69e](https://act-rules.github.io/rules/d0f69e) | -| [valid-lang](https://dequeuniversity.com/rules/axe/4.3/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | | -| [video-caption](https://dequeuniversity.com/rules/axe/4.3/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | [eac66b](https://act-rules.github.io/rules/eac66b) | +| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | +| :------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------- | +| [area-alt](https://dequeuniversity.com/rules/axe/4.3/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | +| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.3/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea) | +| [aria-command-name](https://dequeuniversity.com/rules/axe/4.3/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1) | +| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | | +| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | [6cfa84](https://act-rules.github.io/rules/6cfa84) | +| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.3/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | +| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.3/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | +| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.3/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | +| [aria-required-children](https://dequeuniversity.com/rules/axe/4.3/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | [ff89c9](https://act-rules.github.io/rules/ff89c9) | +| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.3/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | [bc4a75](https://act-rules.github.io/rules/bc4a75), [ff89c9](https://act-rules.github.io/rules/ff89c9) | +| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.3/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | +| [aria-roles](https://dequeuniversity.com/rules/axe/4.3/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | | +| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | | +| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.3/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | +| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea), [c487ae](https://act-rules.github.io/rules/c487ae) | +| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | +| [audio-caption](https://dequeuniversity.com/rules/axe/4.3/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | [c3232f](https://act-rules.github.io/rules/c3232f), [e7aa44](https://act-rules.github.io/rules/e7aa44) | +| [blink](https://dequeuniversity.com/rules/axe/4.3/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | | +| [button-name](https://dequeuniversity.com/rules/axe/4.3/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1), [m6b1q3](https://act-rules.github.io/rules/m6b1q3) | +| [bypass](https://dequeuniversity.com/rules/axe/4.3/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | needs review | | +| [color-contrast](https://dequeuniversity.com/rules/axe/4.3/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | | +| [definition-list](https://dequeuniversity.com/rules/axe/4.3/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [dlitem](https://dequeuniversity.com/rules/axe/4.3/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [document-title](https://dequeuniversity.com/rules/axe/4.3/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | [2779a5](https://act-rules.github.io/rules/2779a5) | +| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | | +| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | +| [duplicate-id](https://dequeuniversity.com/rules/axe/4.3/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | | +| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.3/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | | +| [frame-focusable-content](https://dequeuniversity.com/rules/axe/4.3/frame-focusable-content?application=RuleDescription) | Ensures <frame> and <iframe> elements with focusable content do not have tabindex=-1 | Serious | cat.keyboard, wcag2a, wcag211 | failure, needs review | | +| [frame-title](https://dequeuniversity.com/rules/axe/4.3/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements have an accessible name | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | | +| [html-has-lang](https://dequeuniversity.com/rules/axe/4.3/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | [b5c3f8](https://act-rules.github.io/rules/b5c3f8) | +| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.3/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | [bf051a](https://act-rules.github.io/rules/bf051a) | +| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.3/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | [5b7ae0](https://act-rules.github.io/rules/5b7ae0) | +| [image-alt](https://dequeuniversity.com/rules/axe/4.3/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | +| [input-button-name](https://dequeuniversity.com/rules/axe/4.3/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | | +| [input-image-alt](https://dequeuniversity.com/rules/axe/4.3/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [59796f](https://act-rules.github.io/rules/59796f) | +| [label](https://dequeuniversity.com/rules/axe/4.3/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5), [307n5z](https://act-rules.github.io/rules/307n5z) | +| [link-name](https://dequeuniversity.com/rules/axe/4.3/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | +| [list](https://dequeuniversity.com/rules/axe/4.3/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [listitem](https://dequeuniversity.com/rules/axe/4.3/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [marquee](https://dequeuniversity.com/rules/axe/4.3/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | | +| [meta-refresh](https://dequeuniversity.com/rules/axe/4.3/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag221, wcag224, wcag325 | failure | | +| [nested-interactive](https://dequeuniversity.com/rules/axe/4.3/nested-interactive?application=RuleDescription) | Nested interactive controls are not always announced by screen readers or can cause focus problems for screen readers | Serious | cat.keyboard, wcag2a, wcag412 | failure, needs review | [307n5z](https://act-rules.github.io/rules/307n5z) | +| [object-alt](https://dequeuniversity.com/rules/axe/4.3/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | [8fc3b6](https://act-rules.github.io/rules/8fc3b6) | +| [role-img-alt](https://dequeuniversity.com/rules/axe/4.3/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | +| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.3/scrollable-region-focusable?application=RuleDescription) | Ensure elements that have scrollable content are accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | [0ssw9k](https://act-rules.github.io/rules/0ssw9k) | +| [select-name](https://dequeuniversity.com/rules/axe/4.3/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.3/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | | +| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.3/svg-img-alt?application=RuleDescription) | Ensures <svg> elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [7d6734](https://act-rules.github.io/rules/7d6734) | +| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.3/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table that uses the headers attribute refers only to other cells in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [a25f45](https://act-rules.github.io/rules/a25f45) | +| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.3/th-has-data-cells?application=RuleDescription) | Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [d0f69e](https://act-rules.github.io/rules/d0f69e) | +| [valid-lang](https://dequeuniversity.com/rules/axe/4.3/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | | +| [video-caption](https://dequeuniversity.com/rules/axe/4.3/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | [eac66b](https://act-rules.github.io/rules/eac66b) | ## WCAG 2.1 Level A & AA Rules diff --git a/lib/checks/keyboard/no-focusable-content.json b/lib/checks/keyboard/no-focusable-content.json index 35c40fc77b..79c2f28b19 100644 --- a/lib/checks/keyboard/no-focusable-content.json +++ b/lib/checks/keyboard/no-focusable-content.json @@ -7,7 +7,7 @@ "pass": "Element does not have focusable descendants", "fail": { "default": "Element has focusable descendants", - "notHidden": "Using negative tabindex is not a reliable way of hiding interactive elements" + "notHidden": "Using tabindex=-1 on an element inside an interactive control does not prevent a screen reader from focusing the element (even with 'aria-hidden=true')" }, "incomplete": "Could not determine if element has descendants" } diff --git a/lib/rules/nested-interactive.json b/lib/rules/nested-interactive.json index 5293a7794f..2aa7b88ae9 100644 --- a/lib/rules/nested-interactive.json +++ b/lib/rules/nested-interactive.json @@ -4,8 +4,8 @@ "tags": ["cat.keyboard", "wcag2a", "wcag412"], "actIds": ["307n5z"], "metadata": { - "description": "Ensure controls are not nested as they are not announced by screen readers", - "help": "Interactive controls must not be nested" + "description": "Nested interactive controls are not always announced by screen readers or can cause focus problems for screen readers", + "help": "Ensure interactive controls are not nested" }, "all": [], "any": ["no-focusable-content"], From 46ca22a4c1dc7c11d2a4f513e66497fe25a00d33 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Tue, 26 Oct 2021 20:24:14 -0400 Subject: [PATCH 20/28] add unit test for frame-focusable-content check --- .../keyboard/frame-focusable-content.js | 41 +++++++++++++++++++ 1 file changed, 41 insertions(+) create mode 100644 test/checks/keyboard/frame-focusable-content.js diff --git a/test/checks/keyboard/frame-focusable-content.js b/test/checks/keyboard/frame-focusable-content.js new file mode 100644 index 0000000000..224667aa6e --- /dev/null +++ b/test/checks/keyboard/frame-focusable-content.js @@ -0,0 +1,41 @@ +describe('frame-focusable-content tests', function() { + var fixture = document.querySelector('#fixture'); + var queryFixture = axe.testUtils.queryFixture; + var frameFocusableContent = axe.testUtils.getCheckEvaluate( + 'frame-focusable-content' + ); + + afterEach(function() { + fixture.innerHTML = ''; + }); + + it('should return true if element has no focusable content', function() { + var vNode = queryFixture(''); + assert.isTrue(frameFocusableContent(null, null, vNode)); + }); + + it('should return true if element is empty', function() { + var vNode = queryFixture(''); + assert.isTrue(frameFocusableContent(null, null, vNode)); + }); + + it('should return true if element only has text content', function() { + var vNode = queryFixture(''); + assert.isTrue(frameFocusableContent(null, null, vNode)); + }); + + it('should return false if element has focusable content', function() { + var vNode = queryFixture( + '' + ); + assert.isFalse(frameFocusableContent(null, null, vNode)); + }); + + it('should return false if element has natively focusable content', function() { + var vNode = queryFixture( + '' + ); + assert.isFalse(frameFocusableContent(null, null, vNode)); + }); + +}); From c5c823496cdfe457ce3061ea2a94736c736b5e90 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Tue, 26 Oct 2021 20:40:11 -0400 Subject: [PATCH 21/28] update the no-focusable-content unit tests to add a test to capture negative tabindex --- test/checks/keyboard/no-focusable-content.js | 14 ++++++++++++++ 1 file changed, 14 insertions(+) diff --git a/test/checks/keyboard/no-focusable-content.js b/test/checks/keyboard/no-focusable-content.js index 761bbb547d..70cd4af154 100644 --- a/test/checks/keyboard/no-focusable-content.js +++ b/test/checks/keyboard/no-focusable-content.js @@ -4,9 +4,13 @@ describe('no-focusable-content tests', function() { var noFocusableContent = axe.testUtils.getCheckEvaluate( 'no-focusable-content' ); + var checkSetup = axe.testUtils.checkSetup; + var check = checks['no-focusable-content']; + var checkContext = new axe.testUtils.MockCheckContext(); afterEach(function() { fixture.innerHTML = ''; + checkContext.reset(); }); it('should return true if element has no focusable content', function() { @@ -38,4 +42,14 @@ describe('no-focusable-content tests', function() { assert.isFalse(noFocusableContent(null, null, vNode)); }); + it('should return false if element has natively focusable content with negative tabindex', function() { + var params = checkSetup( + '' + ); + axe.utils.getFlattenedTree(document.documentElement); + assert.isFalse(check.evaluate.apply(checkContext, params)); + assert.deepEqual(checkContext._data, { messageKey: 'notHidden' }); + }); + + }); From 76dda779f703f9e296b7d19aecb43cced6238f5a Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Tue, 26 Oct 2021 20:53:19 -0400 Subject: [PATCH 22/28] update the nested-interactive integration test to add a failure for elements with negative tabindex values --- .../nested-interactive/nested-interactive.html | 2 ++ .../nested-interactive/nested-interactive.json | 13 +++++++++++-- 2 files changed, 13 insertions(+), 2 deletions(-) diff --git a/test/integration/rules/nested-interactive/nested-interactive.html b/test/integration/rules/nested-interactive/nested-interactive.html index beb7fbdf37..fb42dd24dc 100644 --- a/test/integration/rules/nested-interactive/nested-interactive.html +++ b/test/integration/rules/nested-interactive/nested-interactive.html @@ -9,6 +9,8 @@ + + ignored ignored diff --git a/test/integration/rules/nested-interactive/nested-interactive.json b/test/integration/rules/nested-interactive/nested-interactive.json index 78d3b43176..434b22bb90 100644 --- a/test/integration/rules/nested-interactive/nested-interactive.json +++ b/test/integration/rules/nested-interactive/nested-interactive.json @@ -1,13 +1,22 @@ { "description": "nested-interactive tests", "rule": "nested-interactive", - "violations": [["#fail1"], ["#fail2"], ["#fail3"], ["#fail4"], ["#fail5"]], + "violations": [ + ["#fail1"], + ["#fail2"], + ["#fail3"], + ["#fail4"], + ["#fail5"], + ["#fail6"], + ["#fail7"] + ], "passes": [ ["#pass1"], ["#pass2"], ["#pass3"], ["#pass4"], ["#pass5"], - ["#pass6"] + ["#pass6"], + ["#pass7"] ] } From c48c783d09622e7309572c6f039f1a9b7c1311e2 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Thu, 7 Oct 2021 21:18:00 -0400 Subject: [PATCH 23/28] fix(no-focusable-content-for-frame): fix locale files Was broken by recent rename of this check. --- locales/fr.json | 2 +- locales/ja.json | 2 +- locales/ko.json | 2 +- locales/pl.json | 2 +- locales/pt_BR.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index a1cba7785d..1e3a831fe5 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -604,7 +604,7 @@ "pass": "Aucun élément focalisable contenu dans l’élément", "fail": "Le contenu focalisable devrait se voir assigné un tabindex='-1' ou être retiré du DOM" }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "L’élément n’a pas de descendants focalisables", "fail": "L’élément a des descendants focalisables", "incomplete": "Impossible de déterminer si l’élément a des descendants" diff --git a/locales/ja.json b/locales/ja.json index d9b354a254..4451bd2a88 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -590,7 +590,7 @@ "pass": "要素内にフォーカス不可能な要素は含まれていません", "fail": "フォーカス可能なコンテンツは tabindex='-1' を指定するか、DOMから削除するべきです" }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "要素の子孫にフォーカス可能なものはありません", "fail": "要素の子孫にフォーカス可能なものがあります", "incomplete": "要素に子孫があるか判定できませんでした" diff --git a/locales/ko.json b/locales/ko.json index fe18dbf9ae..7b0fbd825c 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -601,7 +601,7 @@ "pass": "엘리먼트 안에 초점을 얻을 수 있는(focusable) 엘리먼트가 없습니다.", "fail": "초점을 얻을 수 있는(focusable) 콘텐츠는 tabindex='-1'을 가지거나 DOM에서 제거되어야 합니다." }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 없습니다.", "fail": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 있습니다.", "incomplete": "엘리먼트에 후손 항목이 있는지 확인할 수 없습니다." diff --git a/locales/pl.json b/locales/pl.json index be299186d2..45a94d4a4c 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -590,7 +590,7 @@ "pass": "Nie ma elementów przyjmujących fokus wewnątrz elementu.", "fail": "Treść przyjmująca fokus powinna mieć tabindex=-1 lub być usunięta z DOM." }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "Element nie ma potomków przyjmujących fokus", "fail": "Element ma elementy potomne przyjmujące fokus", "incomplete": "Nie można ustalić, czy element ma elementy potomne" diff --git a/locales/pt_BR.json b/locales/pt_BR.json index b5441b9c04..3ccfbbf568 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -593,7 +593,7 @@ "pass": "Nenhum elemento focalizável contido no elemento", "fail": "Conteúdo focalizável deve ter tabindex='-1' ou ser removido do DOM" }, - "frame-focusable-content": { + "no-focusable-content-for-frame": { "pass": "O elemento não tem descendentes focalizáveis", "fail": "O elemento tem descendentes focalizáveis", "incomplete": "Não foi possível determinar se o elemento tem descendentes" From 4c7662eb10c42baa269ceec3943d1658aaf26c75 Mon Sep 17 00:00:00 2001 From: Dan Tripp <88439449+dan-tripp@users.noreply.github.com> Date: Tue, 26 Oct 2021 20:55:57 -0400 Subject: [PATCH 24/28] Update lib/rules/nested-interactive.json Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com> --- lib/rules/nested-interactive.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/lib/rules/nested-interactive.json b/lib/rules/nested-interactive.json index 2aa7b88ae9..857aea60f2 100644 --- a/lib/rules/nested-interactive.json +++ b/lib/rules/nested-interactive.json @@ -4,8 +4,8 @@ "tags": ["cat.keyboard", "wcag2a", "wcag412"], "actIds": ["307n5z"], "metadata": { - "description": "Nested interactive controls are not always announced by screen readers or can cause focus problems for screen readers", - "help": "Ensure interactive controls are not nested" + "description": "Ensures interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies", + "help": "Interactive controls must not be nested" }, "all": [], "any": ["no-focusable-content"], From 9aa0e0e1d9f20b07a1d72565995ae65be88f81bb Mon Sep 17 00:00:00 2001 From: Dan Tripp <88439449+dan-tripp@users.noreply.github.com> Date: Tue, 26 Oct 2021 21:01:06 -0400 Subject: [PATCH 25/28] Update lib/checks/keyboard/no-focusable-content.json Co-authored-by: Steven Lambert <2433219+straker@users.noreply.github.com> --- lib/checks/keyboard/no-focusable-content.json | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/lib/checks/keyboard/no-focusable-content.json b/lib/checks/keyboard/no-focusable-content.json index 79c2f28b19..44d114c7b8 100644 --- a/lib/checks/keyboard/no-focusable-content.json +++ b/lib/checks/keyboard/no-focusable-content.json @@ -7,7 +7,7 @@ "pass": "Element does not have focusable descendants", "fail": { "default": "Element has focusable descendants", - "notHidden": "Using tabindex=-1 on an element inside an interactive control does not prevent a screen reader from focusing the element (even with 'aria-hidden=true')" + "notHidden": "Using a negative tabindex on an element inside an interactive control does not prevent a screen reader from focusing the element (even with 'aria-hidden=true')" }, "incomplete": "Could not determine if element has descendants" } From 376540b6f3c37642f9eb49fffd33e12133d341ea Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Wed, 27 Oct 2021 20:52:00 -0400 Subject: [PATCH 26/28] fixing botched merge --- test/checks/keyboard/no-focusable-content.js | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/test/checks/keyboard/no-focusable-content.js b/test/checks/keyboard/no-focusable-content.js index 70cd4af154..8c84f7da81 100644 --- a/test/checks/keyboard/no-focusable-content.js +++ b/test/checks/keyboard/no-focusable-content.js @@ -50,6 +50,5 @@ describe('no-focusable-content tests', function() { assert.isFalse(check.evaluate.apply(checkContext, params)); assert.deepEqual(checkContext._data, { messageKey: 'notHidden' }); }); - - + }); From ba1e4e65fb5be3263aec635408603b5a550ce3a4 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Sun, 31 Oct 2021 21:26:36 -0400 Subject: [PATCH 27/28] update rule-descriptions.md --- doc/rule-descriptions.md | 112 +++++++++++++++++++-------------------- 1 file changed, 56 insertions(+), 56 deletions(-) diff --git a/doc/rule-descriptions.md b/doc/rule-descriptions.md index 0f1d6cca4a..317534812f 100644 --- a/doc/rule-descriptions.md +++ b/doc/rule-descriptions.md @@ -11,62 +11,62 @@ ## WCAG 2.0 Level A & AA Rules -| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | -| :------------------------------------------------------------------------------------------------------------------------------- | :-------------------------------------------------------------------------------------------------------------------- | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------- | -| [area-alt](https://dequeuniversity.com/rules/axe/4.3/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | -| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.3/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea) | -| [aria-command-name](https://dequeuniversity.com/rules/axe/4.3/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1) | -| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | | -| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | [6cfa84](https://act-rules.github.io/rules/6cfa84) | -| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | -| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.3/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | -| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.3/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | -| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.3/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | -| [aria-required-children](https://dequeuniversity.com/rules/axe/4.3/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | [ff89c9](https://act-rules.github.io/rules/ff89c9) | -| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.3/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | [bc4a75](https://act-rules.github.io/rules/bc4a75), [ff89c9](https://act-rules.github.io/rules/ff89c9) | -| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.3/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | -| [aria-roles](https://dequeuniversity.com/rules/axe/4.3/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | | -| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | | -| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.3/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | -| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea), [c487ae](https://act-rules.github.io/rules/c487ae) | -| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | -| [audio-caption](https://dequeuniversity.com/rules/axe/4.3/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | [c3232f](https://act-rules.github.io/rules/c3232f), [e7aa44](https://act-rules.github.io/rules/e7aa44) | -| [blink](https://dequeuniversity.com/rules/axe/4.3/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | | -| [button-name](https://dequeuniversity.com/rules/axe/4.3/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1), [m6b1q3](https://act-rules.github.io/rules/m6b1q3) | -| [bypass](https://dequeuniversity.com/rules/axe/4.3/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | needs review | | -| [color-contrast](https://dequeuniversity.com/rules/axe/4.3/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | | -| [definition-list](https://dequeuniversity.com/rules/axe/4.3/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [dlitem](https://dequeuniversity.com/rules/axe/4.3/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [document-title](https://dequeuniversity.com/rules/axe/4.3/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | [2779a5](https://act-rules.github.io/rules/2779a5) | -| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | | -| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | -| [duplicate-id](https://dequeuniversity.com/rules/axe/4.3/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | | -| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.3/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | | -| [frame-focusable-content](https://dequeuniversity.com/rules/axe/4.3/frame-focusable-content?application=RuleDescription) | Ensures <frame> and <iframe> elements with focusable content do not have tabindex=-1 | Serious | cat.keyboard, wcag2a, wcag211 | failure, needs review | | -| [frame-title](https://dequeuniversity.com/rules/axe/4.3/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements have an accessible name | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | | -| [html-has-lang](https://dequeuniversity.com/rules/axe/4.3/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | [b5c3f8](https://act-rules.github.io/rules/b5c3f8) | -| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.3/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | [bf051a](https://act-rules.github.io/rules/bf051a) | -| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.3/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | [5b7ae0](https://act-rules.github.io/rules/5b7ae0) | -| [image-alt](https://dequeuniversity.com/rules/axe/4.3/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | -| [input-button-name](https://dequeuniversity.com/rules/axe/4.3/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | | -| [input-image-alt](https://dequeuniversity.com/rules/axe/4.3/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [59796f](https://act-rules.github.io/rules/59796f) | -| [label](https://dequeuniversity.com/rules/axe/4.3/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5), [307n5z](https://act-rules.github.io/rules/307n5z) | -| [link-name](https://dequeuniversity.com/rules/axe/4.3/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | -| [list](https://dequeuniversity.com/rules/axe/4.3/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [listitem](https://dequeuniversity.com/rules/axe/4.3/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | | -| [marquee](https://dequeuniversity.com/rules/axe/4.3/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | | -| [meta-refresh](https://dequeuniversity.com/rules/axe/4.3/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag221, wcag224, wcag325 | failure | | -| [nested-interactive](https://dequeuniversity.com/rules/axe/4.3/nested-interactive?application=RuleDescription) | Nested interactive controls are not always announced by screen readers or can cause focus problems for screen readers | Serious | cat.keyboard, wcag2a, wcag412 | failure, needs review | [307n5z](https://act-rules.github.io/rules/307n5z) | -| [object-alt](https://dequeuniversity.com/rules/axe/4.3/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | [8fc3b6](https://act-rules.github.io/rules/8fc3b6) | -| [role-img-alt](https://dequeuniversity.com/rules/axe/4.3/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | -| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.3/scrollable-region-focusable?application=RuleDescription) | Ensure elements that have scrollable content are accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | [0ssw9k](https://act-rules.github.io/rules/0ssw9k) | -| [select-name](https://dequeuniversity.com/rules/axe/4.3/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | -| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.3/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | | -| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.3/svg-img-alt?application=RuleDescription) | Ensures <svg> elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [7d6734](https://act-rules.github.io/rules/7d6734) | -| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.3/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table that uses the headers attribute refers only to other cells in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [a25f45](https://act-rules.github.io/rules/a25f45) | -| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.3/th-has-data-cells?application=RuleDescription) | Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [d0f69e](https://act-rules.github.io/rules/d0f69e) | -| [valid-lang](https://dequeuniversity.com/rules/axe/4.3/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | | -| [video-caption](https://dequeuniversity.com/rules/axe/4.3/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | [eac66b](https://act-rules.github.io/rules/eac66b) | +| Rule ID | Description | Impact | Tags | Issue Type | ACT Rules | +| :------------------------------------------------------------------------------------------------------------------------------- | :---------------------------------------------------------------------------------------------------------------------------------------------------- | :---------------- | :----------------------------------------------------------------------------------------- | :------------------------- | :----------------------------------------------------------------------------------------------------- | +| [area-alt](https://dequeuniversity.com/rules/axe/4.3/area-alt?application=RuleDescription) | Ensures <area> elements of image maps have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, wcag244, wcag412, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | +| [aria-allowed-attr](https://dequeuniversity.com/rules/axe/4.3/aria-allowed-attr?application=RuleDescription) | Ensures ARIA attributes are allowed for an element's role | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea) | +| [aria-command-name](https://dequeuniversity.com/rules/axe/4.3/aria-command-name?application=RuleDescription) | Ensures every ARIA button, link and menuitem has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1) | +| [aria-hidden-body](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-body?application=RuleDescription) | Ensures aria-hidden='true' is not present on the document body. | Critical | cat.aria, wcag2a, wcag412 | failure | | +| [aria-hidden-focus](https://dequeuniversity.com/rules/axe/4.3/aria-hidden-focus?application=RuleDescription) | Ensures aria-hidden elements do not contain focusable elements | Serious | cat.name-role-value, wcag2a, wcag412, wcag131 | failure, needs review | [6cfa84](https://act-rules.github.io/rules/6cfa84) | +| [aria-input-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-input-field-name?application=RuleDescription) | Ensures every ARIA input field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [aria-meter-name](https://dequeuniversity.com/rules/axe/4.3/aria-meter-name?application=RuleDescription) | Ensures every ARIA meter node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | +| [aria-progressbar-name](https://dequeuniversity.com/rules/axe/4.3/aria-progressbar-name?application=RuleDescription) | Ensures every ARIA progressbar node has an accessible name | Serious | cat.aria, wcag2a, wcag111 | failure, needs review | | +| [aria-required-attr](https://dequeuniversity.com/rules/axe/4.3/aria-required-attr?application=RuleDescription) | Ensures elements with ARIA roles have all required ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | +| [aria-required-children](https://dequeuniversity.com/rules/axe/4.3/aria-required-children?application=RuleDescription) | Ensures elements with an ARIA role that require child roles contain them | Critical | cat.aria, wcag2a, wcag131 | failure, needs review | [ff89c9](https://act-rules.github.io/rules/ff89c9) | +| [aria-required-parent](https://dequeuniversity.com/rules/axe/4.3/aria-required-parent?application=RuleDescription) | Ensures elements with an ARIA role that require parent roles are contained by them | Critical | cat.aria, wcag2a, wcag131 | failure | [bc4a75](https://act-rules.github.io/rules/bc4a75), [ff89c9](https://act-rules.github.io/rules/ff89c9) | +| [aria-roledescription](https://dequeuniversity.com/rules/axe/4.3/aria-roledescription?application=RuleDescription) | Ensure aria-roledescription is only used on elements with an implicit or explicit role | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | +| [aria-roles](https://dequeuniversity.com/rules/axe/4.3/aria-roles?application=RuleDescription) | Ensures all elements with a role attribute use a valid value | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | | +| [aria-toggle-field-name](https://dequeuniversity.com/rules/axe/4.3/aria-toggle-field-name?application=RuleDescription) | Ensures every ARIA toggle field has an accessible name | Moderate, Serious | cat.aria, wcag2a, wcag412, ACT | failure, needs review | | +| [aria-tooltip-name](https://dequeuniversity.com/rules/axe/4.3/aria-tooltip-name?application=RuleDescription) | Ensures every ARIA tooltip node has an accessible name | Serious | cat.aria, wcag2a, wcag412 | failure, needs review | | +| [aria-valid-attr-value](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr-value?application=RuleDescription) | Ensures all ARIA attributes have valid values | Serious, Critical | cat.aria, wcag2a, wcag412 | failure, needs review | [5c01ea](https://act-rules.github.io/rules/5c01ea), [c487ae](https://act-rules.github.io/rules/c487ae) | +| [aria-valid-attr](https://dequeuniversity.com/rules/axe/4.3/aria-valid-attr?application=RuleDescription) | Ensures attributes that begin with aria- are valid ARIA attributes | Critical | cat.aria, wcag2a, wcag412 | failure | | +| [audio-caption](https://dequeuniversity.com/rules/axe/4.3/audio-caption?application=RuleDescription) | Ensures <audio> elements have captions | Critical | cat.time-and-media, wcag2a, wcag121, section508, section508.22.a | needs review | [c3232f](https://act-rules.github.io/rules/c3232f), [e7aa44](https://act-rules.github.io/rules/e7aa44) | +| [blink](https://dequeuniversity.com/rules/axe/4.3/blink?application=RuleDescription) | Ensures <blink> elements are not used | Serious | cat.time-and-media, wcag2a, wcag222, section508, section508.22.j | failure | | +| [button-name](https://dequeuniversity.com/rules/axe/4.3/button-name?application=RuleDescription) | Ensures buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a, ACT | failure, needs review | [97a4e1](https://act-rules.github.io/rules/97a4e1), [m6b1q3](https://act-rules.github.io/rules/m6b1q3) | +| [bypass](https://dequeuniversity.com/rules/axe/4.3/bypass?application=RuleDescription) | Ensures each page has at least one mechanism for a user to bypass navigation and jump straight to the content | Serious | cat.keyboard, wcag2a, wcag241, section508, section508.22.o | needs review | | +| [color-contrast](https://dequeuniversity.com/rules/axe/4.3/color-contrast?application=RuleDescription) | Ensures the contrast between foreground and background colors meets WCAG 2 AA contrast ratio thresholds | Serious | cat.color, wcag2aa, wcag143 | failure, needs review | | +| [definition-list](https://dequeuniversity.com/rules/axe/4.3/definition-list?application=RuleDescription) | Ensures <dl> elements are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [dlitem](https://dequeuniversity.com/rules/axe/4.3/dlitem?application=RuleDescription) | Ensures <dt> and <dd> elements are contained by a <dl> | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [document-title](https://dequeuniversity.com/rules/axe/4.3/document-title?application=RuleDescription) | Ensures each HTML document contains a non-empty <title> element | Serious | cat.text-alternatives, wcag2a, wcag242, ACT | failure | [2779a5](https://act-rules.github.io/rules/2779a5) | +| [duplicate-id-active](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-active?application=RuleDescription) | Ensures every id attribute value of active elements is unique | Serious | cat.parsing, wcag2a, wcag411 | failure | | +| [duplicate-id-aria](https://dequeuniversity.com/rules/axe/4.3/duplicate-id-aria?application=RuleDescription) | Ensures every id attribute value used in ARIA and in labels is unique | Critical | cat.parsing, wcag2a, wcag411 | failure | [3ea0c8](https://act-rules.github.io/rules/3ea0c8) | +| [duplicate-id](https://dequeuniversity.com/rules/axe/4.3/duplicate-id?application=RuleDescription) | Ensures every id attribute value is unique | Minor | cat.parsing, wcag2a, wcag411 | failure | | +| [form-field-multiple-labels](https://dequeuniversity.com/rules/axe/4.3/form-field-multiple-labels?application=RuleDescription) | Ensures form field does not have multiple label elements | Moderate | cat.forms, wcag2a, wcag332 | needs review | | +| [frame-focusable-content](https://dequeuniversity.com/rules/axe/4.3/frame-focusable-content?application=RuleDescription) | Ensures <frame> and <iframe> elements with focusable content do not have tabindex=-1 | Serious | cat.keyboard, wcag2a, wcag211 | failure, needs review | | +| [frame-title](https://dequeuniversity.com/rules/axe/4.3/frame-title?application=RuleDescription) | Ensures <iframe> and <frame> elements have an accessible name | Serious | cat.text-alternatives, wcag2a, wcag241, wcag412, section508, section508.22.i | failure, needs review | | +| [html-has-lang](https://dequeuniversity.com/rules/axe/4.3/html-has-lang?application=RuleDescription) | Ensures every HTML document has a lang attribute | Serious | cat.language, wcag2a, wcag311, ACT | failure | [b5c3f8](https://act-rules.github.io/rules/b5c3f8) | +| [html-lang-valid](https://dequeuniversity.com/rules/axe/4.3/html-lang-valid?application=RuleDescription) | Ensures the lang attribute of the <html> element has a valid value | Serious | cat.language, wcag2a, wcag311, ACT | failure | [bf051a](https://act-rules.github.io/rules/bf051a) | +| [html-xml-lang-mismatch](https://dequeuniversity.com/rules/axe/4.3/html-xml-lang-mismatch?application=RuleDescription) | Ensure that HTML elements with both valid lang and xml:lang attributes agree on the base language of the page | Moderate | cat.language, wcag2a, wcag311, ACT | failure | [5b7ae0](https://act-rules.github.io/rules/5b7ae0) | +| [image-alt](https://dequeuniversity.com/rules/axe/4.3/image-alt?application=RuleDescription) | Ensures <img> elements have alternate text or a role of none or presentation | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | +| [input-button-name](https://dequeuniversity.com/rules/axe/4.3/input-button-name?application=RuleDescription) | Ensures input buttons have discernible text | Critical | cat.name-role-value, wcag2a, wcag412, section508, section508.22.a | failure, needs review | | +| [input-image-alt](https://dequeuniversity.com/rules/axe/4.3/input-image-alt?application=RuleDescription) | Ensures <input type="image"> elements have alternate text | Critical | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [59796f](https://act-rules.github.io/rules/59796f) | +| [label](https://dequeuniversity.com/rules/axe/4.3/label?application=RuleDescription) | Ensures every form element has a label | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5), [307n5z](https://act-rules.github.io/rules/307n5z) | +| [link-name](https://dequeuniversity.com/rules/axe/4.3/link-name?application=RuleDescription) | Ensures links have discernible text | Serious | cat.name-role-value, wcag2a, wcag412, wcag244, section508, section508.22.a, ACT | failure, needs review | [c487ae](https://act-rules.github.io/rules/c487ae) | +| [list](https://dequeuniversity.com/rules/axe/4.3/list?application=RuleDescription) | Ensures that lists are structured correctly | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [listitem](https://dequeuniversity.com/rules/axe/4.3/listitem?application=RuleDescription) | Ensures <li> elements are used semantically | Serious | cat.structure, wcag2a, wcag131 | failure | | +| [marquee](https://dequeuniversity.com/rules/axe/4.3/marquee?application=RuleDescription) | Ensures <marquee> elements are not used | Serious | cat.parsing, wcag2a, wcag222 | failure | | +| [meta-refresh](https://dequeuniversity.com/rules/axe/4.3/meta-refresh?application=RuleDescription) | Ensures <meta http-equiv="refresh"> is not used | Critical | cat.time-and-media, wcag2a, wcag221, wcag224, wcag325 | failure | | +| [nested-interactive](https://dequeuniversity.com/rules/axe/4.3/nested-interactive?application=RuleDescription) | Ensures interactive controls are not nested as they are not always announced by screen readers or can cause focus problems for assistive technologies | Serious | cat.keyboard, wcag2a, wcag412 | failure, needs review | [307n5z](https://act-rules.github.io/rules/307n5z) | +| [object-alt](https://dequeuniversity.com/rules/axe/4.3/object-alt?application=RuleDescription) | Ensures <object> elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a | failure, needs review | [8fc3b6](https://act-rules.github.io/rules/8fc3b6) | +| [role-img-alt](https://dequeuniversity.com/rules/axe/4.3/role-img-alt?application=RuleDescription) | Ensures [role='img'] elements have alternate text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [23a2a8](https://act-rules.github.io/rules/23a2a8) | +| [scrollable-region-focusable](https://dequeuniversity.com/rules/axe/4.3/scrollable-region-focusable?application=RuleDescription) | Ensure elements that have scrollable content are accessible by keyboard | Moderate | cat.keyboard, wcag2a, wcag211 | failure | [0ssw9k](https://act-rules.github.io/rules/0ssw9k) | +| [select-name](https://dequeuniversity.com/rules/axe/4.3/select-name?application=RuleDescription) | Ensures select element has an accessible name | Minor, Critical | cat.forms, wcag2a, wcag412, wcag131, section508, section508.22.n, ACT | failure, needs review | [e086e5](https://act-rules.github.io/rules/e086e5) | +| [server-side-image-map](https://dequeuniversity.com/rules/axe/4.3/server-side-image-map?application=RuleDescription) | Ensures that server-side image maps are not used | Minor | cat.text-alternatives, wcag2a, wcag211, section508, section508.22.f | needs review | | +| [svg-img-alt](https://dequeuniversity.com/rules/axe/4.3/svg-img-alt?application=RuleDescription) | Ensures <svg> elements with an img, graphics-document or graphics-symbol role have an accessible text | Serious | cat.text-alternatives, wcag2a, wcag111, section508, section508.22.a, ACT | failure, needs review | [7d6734](https://act-rules.github.io/rules/7d6734) | +| [td-headers-attr](https://dequeuniversity.com/rules/axe/4.3/td-headers-attr?application=RuleDescription) | Ensure that each cell in a table that uses the headers attribute refers only to other cells in that table | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [a25f45](https://act-rules.github.io/rules/a25f45) | +| [th-has-data-cells](https://dequeuniversity.com/rules/axe/4.3/th-has-data-cells?application=RuleDescription) | Ensure that <th> elements and elements with role=columnheader/rowheader have data cells they describe | Serious | cat.tables, wcag2a, wcag131, section508, section508.22.g | failure, needs review | [d0f69e](https://act-rules.github.io/rules/d0f69e) | +| [valid-lang](https://dequeuniversity.com/rules/axe/4.3/valid-lang?application=RuleDescription) | Ensures lang attributes have valid values | Serious | cat.language, wcag2aa, wcag312 | failure | | +| [video-caption](https://dequeuniversity.com/rules/axe/4.3/video-caption?application=RuleDescription) | Ensures <video> elements have captions | Critical | cat.text-alternatives, wcag2a, wcag122, section508, section508.22.a | needs review | [eac66b](https://act-rules.github.io/rules/eac66b) | ## WCAG 2.1 Level A & AA Rules From f785edbd78442cf3690f652b166f7751f1c4dfc3 Mon Sep 17 00:00:00 2001 From: Dan Tripp Date: Tue, 2 Nov 2021 06:54:30 -0400 Subject: [PATCH 28/28] fix locale files --- locales/fr.json | 2 +- locales/ja.json | 2 +- locales/ko.json | 2 +- locales/pl.json | 2 +- locales/pt_BR.json | 2 +- 5 files changed, 5 insertions(+), 5 deletions(-) diff --git a/locales/fr.json b/locales/fr.json index 1e3a831fe5..a1cba7785d 100644 --- a/locales/fr.json +++ b/locales/fr.json @@ -604,7 +604,7 @@ "pass": "Aucun élément focalisable contenu dans l’élément", "fail": "Le contenu focalisable devrait se voir assigné un tabindex='-1' ou être retiré du DOM" }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "L’élément n’a pas de descendants focalisables", "fail": "L’élément a des descendants focalisables", "incomplete": "Impossible de déterminer si l’élément a des descendants" diff --git a/locales/ja.json b/locales/ja.json index 4451bd2a88..d9b354a254 100644 --- a/locales/ja.json +++ b/locales/ja.json @@ -590,7 +590,7 @@ "pass": "要素内にフォーカス不可能な要素は含まれていません", "fail": "フォーカス可能なコンテンツは tabindex='-1' を指定するか、DOMから削除するべきです" }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "要素の子孫にフォーカス可能なものはありません", "fail": "要素の子孫にフォーカス可能なものがあります", "incomplete": "要素に子孫があるか判定できませんでした" diff --git a/locales/ko.json b/locales/ko.json index 7b0fbd825c..fe18dbf9ae 100644 --- a/locales/ko.json +++ b/locales/ko.json @@ -601,7 +601,7 @@ "pass": "엘리먼트 안에 초점을 얻을 수 있는(focusable) 엘리먼트가 없습니다.", "fail": "초점을 얻을 수 있는(focusable) 콘텐츠는 tabindex='-1'을 가지거나 DOM에서 제거되어야 합니다." }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 없습니다.", "fail": "엘리먼트에 초점을 얻을 수 있는(focusable) 후손 항목이 있습니다.", "incomplete": "엘리먼트에 후손 항목이 있는지 확인할 수 없습니다." diff --git a/locales/pl.json b/locales/pl.json index 45a94d4a4c..be299186d2 100644 --- a/locales/pl.json +++ b/locales/pl.json @@ -590,7 +590,7 @@ "pass": "Nie ma elementów przyjmujących fokus wewnątrz elementu.", "fail": "Treść przyjmująca fokus powinna mieć tabindex=-1 lub być usunięta z DOM." }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "Element nie ma potomków przyjmujących fokus", "fail": "Element ma elementy potomne przyjmujące fokus", "incomplete": "Nie można ustalić, czy element ma elementy potomne" diff --git a/locales/pt_BR.json b/locales/pt_BR.json index 3ccfbbf568..b5441b9c04 100644 --- a/locales/pt_BR.json +++ b/locales/pt_BR.json @@ -593,7 +593,7 @@ "pass": "Nenhum elemento focalizável contido no elemento", "fail": "Conteúdo focalizável deve ter tabindex='-1' ou ser removido do DOM" }, - "no-focusable-content-for-frame": { + "frame-focusable-content": { "pass": "O elemento não tem descendentes focalizáveis", "fail": "O elemento tem descendentes focalizáveis", "incomplete": "Não foi possível determinar se o elemento tem descendentes"