diff --git a/src/__tests__/ariaAttributes.js b/src/__tests__/ariaAttributes.js
index 3f504c87..e207721a 100644
--- a/src/__tests__/ariaAttributes.js
+++ b/src/__tests__/ariaAttributes.js
@@ -9,6 +9,15 @@ test('`selected` throws on unsupported roles', () => {
)
})
+test('`pressed` throws on unsupported roles', () => {
+ const {getByRole} = render(``)
+ expect(() =>
+ getByRole('textbox', {pressed: true}),
+ ).toThrowErrorMatchingInlineSnapshot(
+ `"\\"aria-pressed\\" is not supported on role \\"textbox\\"."`,
+ )
+})
+
test('`checked` throws on unsupported roles', () => {
const {getByRole} = render(``)
expect(() =>
@@ -136,3 +145,25 @@ test('`selected: true` matches `aria-selected="true"` on supported roles', () =>
'selected-tab',
])
})
+
+test('`pressed: true|false` matches `pressed` buttons', () => {
+ const {getByRole} = renderIntoDocument(
+ `
+
+
+
`,
+ )
+ expect(getByRole('button', {pressed: true})).toBeInTheDocument()
+ expect(getByRole('button', {pressed: false})).toBeInTheDocument()
+})
+
+test('`pressed: true|false` matches `pressed` elements with proper role', () => {
+ const {getByRole} = renderIntoDocument(
+ `
+ ✔
+ 𝒙
+
`,
+ )
+ expect(getByRole('button', {pressed: true})).toBeInTheDocument()
+ expect(getByRole('button', {pressed: false})).toBeInTheDocument()
+})
diff --git a/src/queries/role.js b/src/queries/role.js
index f9be4564..8ecd230f 100644
--- a/src/queries/role.js
+++ b/src/queries/role.js
@@ -3,6 +3,7 @@ import {roles as allRoles} from 'aria-query'
import {
computeAriaSelected,
computeAriaChecked,
+ computeAriaPressed,
getImplicitAriaRoles,
prettyRoles,
isInaccessible,
@@ -31,6 +32,7 @@ function queryAllByRole(
queryFallbacks = false,
selected,
checked,
+ pressed,
} = {},
) {
checkContainerType(container)
@@ -51,6 +53,13 @@ function queryAllByRole(
}
}
+ if (pressed !== undefined) {
+ // guard against unknown roles
+ if (allRoles.get(role)?.props['aria-pressed'] === undefined) {
+ throw new Error(`"aria-pressed" is not supported on role "${role}".`)
+ }
+ }
+
const subtreeIsInaccessibleCache = new WeakMap()
function cachedIsSubtreeInaccessible(element) {
if (!subtreeIsInaccessibleCache.has(element)) {
@@ -94,6 +103,9 @@ function queryAllByRole(
if (checked !== undefined) {
return checked === computeAriaChecked(element)
}
+ if (pressed !== undefined) {
+ return pressed === computeAriaPressed(element)
+ }
// don't care if aria attributes are unspecified
return true
})
diff --git a/src/role-helpers.js b/src/role-helpers.js
index 10112b0e..47dc05e5 100644
--- a/src/role-helpers.js
+++ b/src/role-helpers.js
@@ -209,6 +209,15 @@ function computeAriaChecked(element) {
return checkBooleanAttribute(element, 'aria-checked')
}
+/**
+ * @param {Element} element -
+ * @returns {boolean | undefined} - false/true if (not)pressed, undefined if not press-able
+ */
+function computeAriaPressed(element) {
+ // https://www.w3.org/TR/wai-aria-1.1/#aria-pressed
+ return checkBooleanAttribute(element, 'aria-pressed')
+}
+
function checkBooleanAttribute(element, attribute) {
const attributeValue = element.getAttribute(attribute)
if (attributeValue === 'true') {
@@ -229,4 +238,5 @@ export {
isInaccessible,
computeAriaSelected,
computeAriaChecked,
+ computeAriaPressed,
}
diff --git a/types/queries.d.ts b/types/queries.d.ts
index e84b6700..13056da7 100644
--- a/types/queries.d.ts
+++ b/types/queries.d.ts
@@ -83,6 +83,11 @@ export interface ByRoleOptions extends MatcherOptions {
* checked in the accessibility tree, i.e., `aria-checked="true"`
*/
checked?: boolean
+ /**
+ * If true only includes elements in the query set that are marked as
+ * pressed in the accessibility tree, i.e., `aria-pressed="true"`
+ */
+ pressed?: boolean
/**
* Includes every role used in the `role` attribute
* For example *ByRole('progressbar', {queryFallbacks: true})` will find `.