Для работы с aria-query необходимо сначала установить пакет через npm:
npm install aria-query
После установки его можно подключить в проекте:
const { roles, aria } = require('aria-query');
roles содержит информацию о доступных ARIA-ролях и их
свойствах, а aria — о доступных атрибутах ARIA и их
возможных значениях. Эти структуры данных представляют собой карты
(Map), которые можно использовать для проверки соответствия элементов
требованиям ARIA.
ARIA-контекст определяет, какие роли и атрибуты могут применяться к элементу в конкретной позиции DOM. Контекст включает в себя:
aria-query предоставляет статические данные о ролях, их
свойствах, требованиях к родителям и допустимых дочерних ролях. Эти
данные позволяют создавать функции проверки валидности контекста
использования ARIA-элементов.
Каждая роль в aria-query описана объектом с ключевыми свойствами:
abstract — флаг, указывающий, что роль абстрактная и не
используется напрямую в DOMrequiredProps — массив обязательных атрибутовprops — все возможные атрибуты ролиbaseConcepts — базовые HTML-элементы, на которых роль
может быть примененаrequiredContextRole — массив ролей, в которых элемент
может находитьсяchildRoles — роли, которые допустимо использовать
внутри данного элементаПример проверки роли кнопки:
const buttonRole = roles.get('button');
console.log(buttonRole.abstract); // false
console.log(buttonRole.requiredProps); // []
console.log(buttonRole.requiredContextRole); // []
console.log(buttonRole.baseConcepts); // [{ module: 'HTML', concept: 'button' }]
Если abstract равен true, напрямую
применять такую роль к элементу нельзя — она служит шаблоном для
производных ролей.
Для проверки допустимости роли элемента внутри определённого родителя
можно использовать свойство requiredContextRole:
const listItemRole = roles.get('listitem');
console.log(listItemRole.requiredContextRole); // ['list', 'group', 'directory', 'menu']
Это означает, что с ролью
listitem корректно использовать только внутри элементов с
ролями list, group, directory или
menu.
Функция проверки может выглядеть так:
function isRoleAllowedInParent(childRole, parentRole) {
const roleData = roles.get(childRole);
if (!roleData) return false;
if (!roleData.requiredContextRole.length) return true;
return roleData.requiredContextRole.includes(parentRole);
}
console.log(isRoleAllowedInParent('listitem', 'list')); // true
console.log(isRoleAllowedInParent('listitem', 'button')); // false
Свойство childRoles описывает, какие роли могут быть
вложены в текущий элемент:
const listRole = roles.get('list');
console.log(listRole.childRoles); // ['listitem', 'group', 'presentation']
Функция проверки дочернего элемента:
function canChildBePlaced(parentRole, childRole) {
const parentData = roles.get(parentRole);
if (!parentData || !parentData.childRoles) return false;
return parentData.childRoles.includes(childRole);
}
console.log(canChildBePlaced('list', 'listitem')); // true
console.log(canChildBePlaced('list', 'button')); // false
Каждая роль содержит свойства requiredProps и
props, где указаны атрибуты ARIA, которые необходимо или
допустимо использовать:
const checkboxRole = roles.get('checkbox');
console.log(checkboxRole.requiredProps); // []
console.log(checkboxRole.props); // ['aria-checked', 'aria-disabled', ...]
Можно проверить, что элемент имеет все обязательные атрибуты:
function hasRequiredProps(role, elementProps) {
const roleData = roles.get(role);
return roleData.requiredProps.every(prop => prop in elementProps);
}
console.log(hasRequiredProps('checkbox', { 'aria-checked': true })); // true
console.log(hasRequiredProps('checkbox', {})); // false
Для сложных компонентов, таких как таблицы, меню или
деревья, важно учитывать сочетание контекста родителя,
допустимых дочерних ролей и атрибутов. aria-query позволяет
строить универсальные валидаторы:
function validateAriaElement(role, parentRole, elementProps, childrenRoles = []) {
if (!roles.has(role)) return false;
if (!isRoleAllowedInParent(role, parentRole)) return false;
if (!hasRequiredProps(role, elementProps)) return false;
const parentData = roles.get(role);
return childrenRoles.every(child => canChildBePlaced(role, child));
}
Пример проверки дерева:
validateAriaElement(
'list',
null,
{},
['listitem', 'listitem']
); // true
Свойство aria в aria-query содержит
информацию о всех доступных атрибутах ARIA:
console.log(aria.has('aria-checked')); // true
console.log(aria.get('aria-checked'));
// { type: 'tristate', relatedRoles: ['checkbox'], values: [true, false, 'mixed'] }
Это позволяет проверять, что значение атрибута соответствует ожидаемому типу и связанным ролям:
function isAriaValueValid(attr, value) {
if (!aria.has(attr)) return false;
const attrData = aria.get(attr);
return attrData.values.includes(value);
}
console.log(isAriaValueValid('aria-checked', 'mixed')); // true
console.log(isAriaValueValid('aria-checked', 'yes')); // false
aria-query идеально подходит для использования с
линтерами и тестовыми фреймворками:
Используя aria-query, можно создавать собственные валидаторы, которые анализируют DOM-структуру и гарантируют корректность ARIA-контекста на всех уровнях компонентов.