Библиотека Aria-query предоставляет структурированные данные о ARIA-ролях и атрибутах, которые помогают анализировать семантику элементов HTML и создавать доступные интерфейсы. Центральное понятие — объект roles, представляющий каждую ARIA-роль как набор свойств: поддерживаемые атрибуты, состояния и допустимые контейнеры.
Каждая роль описывается в виде:
{
name: "button",
abstract: false,
superClass: ["command"],
requiredProps: [],
supportedProps: ["aria-pressed", "aria-expanded"],
requiredContextRole: null,
ownedBy: null
}
Aria-query позволяет получить все известные роли через объект
roles:
import { roles } from 'aria-query';
console.log([...roles.keys()]);
Это возвращает массив строк с именами всех ARIA-ролей, включая как abstract, так и конкретные роли.
Для поиска ролей, которые поддерживают определённый ARIA-атрибут,
используется фильтрация roles:
const attribute = 'aria-expanded';
const rolesWithAttr = [...roles.entries()]
.filter(([roleName, roleData]) => roleData.supportedProps.includes(attribute))
.map(([roleName]) => roleName);
console.log(rolesWithAttr);
Ключевые моменты:
supportedProps содержит все атрибуты, разрешённые для
роли.aria-expanded) или состояние выбора
(aria-checked).Некоторые роли требуют, чтобы их родитель имел определённую роль или
был контейнером конкретного типа. Это задаётся через
requiredContextRole и ownedBy.
Пример поиска ролей, которые могут находиться внутри списка
(list):
const parentRole = 'list';
const childRoles = [...roles.entries()]
.filter(([roleName, roleData]) => roleData.requiredContextRole === parentRole || (roleData.ownedBy && roleData.ownedBy.includes(parentRole)))
.map(([roleName]) => roleName);
console.log(childRoles);
requiredContextRole гарантирует, что элемент будет
валиден только внутри определённого родителя.ownedBy указывает на роли контейнеров, которые могут
владеть данной ролью.Абстрактные роли (abstract: true) не используются
напрямую в DOM, но служат для классификации и наследования.
Для фильтрации конкретных ролей используется:
const concreteRoles = [...roles.entries()]
.filter(([_, roleData]) => !roleData.abstract)
.map(([roleName]) => roleName);
console.log(concreteRoles);
command или
widget, служат только для объединения семантики нескольких
конкретных ролей.Поиск интерактивных ролей с
aria-checked:
const interactiveRoles = [...roles.entries()]
.filter(([_, roleData]) => roleData.supportedProps.includes('aria-checked') && !roleData.abstract)
.map(([roleName]) => roleName);
console.log(interactiveRoles); // ["checkbox", "menuitemcheckbox", "radio"]
Поиск ролей, которые можно использовать внутри
table:
const tableChildRoles = [...roles.entries()]
.filter(([_, roleData]) => roleData.requiredContextRole === 'table' || (roleData.ownedBy && roleData.ownedBy.includes('table')))
.map(([roleName]) => roleName);
console.log(tableChildRoles); // ["row", "rowgroup", "cell", ...]
supportedProps позволяет находить роли по
атрибутам.requiredContextRole и ownedBy
обеспечивает правильную вложенность элементов.Такой подход позволяет создавать динамические проверки доступности интерфейсов, формировать рекомендации по ролям для компонентов и обеспечивать соответствие спецификации ARIA.