diff --git a/src/__tests__/role-helpers.js b/src/__tests__/role-helpers.js
index aadc1dc2..6624ed7a 100644
--- a/src/__tests__/role-helpers.js
+++ b/src/__tests__/role-helpers.js
@@ -3,6 +3,7 @@ import {
logRoles,
getImplicitAriaRoles,
isInaccessible,
+ computeAriaLevel,
} from '../role-helpers'
import {render} from './helpers/test-utils'
@@ -72,6 +73,28 @@ function setup() {
Definition
+
+
+ -
+ Projects
+
+ -
+ project-1.docx
+
+ -
+ project-2.docx
+
+ -
+ Project 3
+
+
+
+
+
`)
return {
@@ -107,6 +130,9 @@ function setup() {
dt: getByTestId('a-dt'),
dd: getByTestId('a-dd'),
header: getByTestId('a-header'),
+ tree: getByTestId('a-tree'),
+ treeItem2: getByTestId('level2-treeitem'),
+ treeItem3: getByTestId('level3-treeitem'),
}
}
@@ -200,3 +226,12 @@ test.each([
expect(isInaccessible(container.querySelector('button'))).toBe(expected)
})
+
+test('computeAriaLevel', () => {
+ const {treeItem2, treeItem3, h1, h2, h3} = setup()
+ expect(computeAriaLevel(treeItem2)).toBe(2)
+ expect(computeAriaLevel(treeItem3)).toBe(3)
+ expect(computeAriaLevel(h1)).toBe(1)
+ expect(computeAriaLevel(h2)).toBe(2)
+ expect(computeAriaLevel(h3)).toBe(3)
+})
diff --git a/src/queries/role.js b/src/queries/role.js
index 339647a6..ec113162 100644
--- a/src/queries/role.js
+++ b/src/queries/role.js
@@ -6,7 +6,7 @@ import {
computeAriaPressed,
computeAriaCurrent,
computeAriaExpanded,
- computeHeadingLevel,
+ computeAriaLevel,
getImplicitAriaRoles,
prettyRoles,
isInaccessible,
@@ -148,7 +148,7 @@ function queryAllByRole(
return expanded === computeAriaExpanded(element)
}
if (level !== undefined) {
- return level === computeHeadingLevel(element)
+ return level === computeAriaLevel(element)
}
// don't care if aria attributes are unspecified
return true
diff --git a/src/role-helpers.js b/src/role-helpers.js
index 7de55932..80ad45ee 100644
--- a/src/role-helpers.js
+++ b/src/role-helpers.js
@@ -280,6 +280,50 @@ function checkBooleanAttribute(element, attribute) {
return undefined
}
+/**
+ * @param {Element} element -
+ * @returns {number | undefined} - number if implicit heading or aria-level present, otherwise undefined
+ */
+function computeTreeItemLevel(element, level) {
+ // https://www.w3.org/TR/wai-aria-1.1/#treeitem
+ // https://www.w3.org/TR/wai-aria-1.1/#aria-level
+ if (element.getAttribute('role') === 'tree') {
+ return level
+ }
+
+ if (element.getAttribute('role') === 'treeitem') {
+ level += 1
+ }
+
+ if (element.parentElement) {
+ return computeTreeItemLevel(element.parentElement, level)
+ }
+
+ return undefined
+}
+
+/**
+ * @param {Element} element -
+ * @returns {number | undefined} - number if implicit aria-level can be inferred or aria-level present, otherwise undefined
+ */
+function computeAriaLevel(element) {
+ // implicit aria-level
+ if (element.getAttribute('role') === 'treeitem') {
+ return computeTreeItemLevel(element, 0)
+ }
+ if (getImplicitAriaRoles(element).includes('heading')) {
+ return computeHeadingLevel(element)
+ }
+
+ // explicit aria-level value
+ // https://www.w3.org/TR/wai-aria-1.2/#aria-level
+ const ariaLevelAttribute =
+ element.getAttribute('aria-level') &&
+ Number(element.getAttribute('aria-level'))
+
+ return ariaLevelAttribute
+}
+
/**
* @param {Element} element -
* @returns {number | undefined} - number if implicit heading or aria-level present, otherwise undefined
@@ -295,13 +339,8 @@ function computeHeadingLevel(element) {
H5: 5,
H6: 6,
}
- // explicit aria-level value
- // https://www.w3.org/TR/wai-aria-1.2/#aria-level
- const ariaLevelAttribute =
- element.getAttribute('aria-level') &&
- Number(element.getAttribute('aria-level'))
- return ariaLevelAttribute || implicitHeadingLevels[element.tagName]
+ return implicitHeadingLevels[element.tagName]
}
export {
@@ -316,5 +355,5 @@ export {
computeAriaPressed,
computeAriaCurrent,
computeAriaExpanded,
- computeHeadingLevel,
+ computeAriaLevel,
}