Проверка контекста использования

Для работы с aria-query необходимо сначала установить пакет через npm:

npm install aria-query

После установки его можно подключить в проекте:

const { roles, aria } = require('aria-query');

roles содержит информацию о доступных ARIA-ролях и их свойствах, а aria — о доступных атрибутах ARIA и их возможных значениях. Эти структуры данных представляют собой карты (Map), которые можно использовать для проверки соответствия элементов требованиям ARIA.


Основные концепции

ARIA-контекст определяет, какие роли и атрибуты могут применяться к элементу в конкретной позиции DOM. Контекст включает в себя:

  • Родительский элемент и его роль
  • Разрешённые дочерние роли
  • Атрибуты ARIA, допустимые для конкретной роли

aria-query предоставляет статические данные о ролях, их свойствах, требованиях к родителям и допустимых дочерних ролях. Эти данные позволяют создавать функции проверки валидности контекста использования ARIA-элементов.


Проверка роли элемента

Каждая роль в aria-query описана объектом с ключевыми свойствами:

  • abstract — флаг, указывающий, что роль абстрактная и не используется напрямую в DOM
  • requiredProps — массив обязательных атрибутов
  • 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

    Проверка атрибутов ARIA

    Каждая роль содержит свойства 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 в 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 идеально подходит для использования с линтерами и тестовыми фреймворками:

    • eslint-plugin-jsx-a11y — проверка ARIA в JSX
    • jest-axe — автоматическая проверка доступности компонентов
    • Playwright / Cypress — интеграция проверки ролей и атрибутов при e2e тестах

    Используя aria-query, можно создавать собственные валидаторы, которые анализируют DOM-структуру и гарантируют корректность ARIA-контекста на всех уровнях компонентов.