Библиотека Aria-query предоставляет средства для работы с ARIA-ролями и атрибутами в JavaScript, позволяя создавать доступные пользовательские интерфейсы. Одной из ключевых возможностей является использование ролей для нестандартных элементов, то есть элементов, которые не имеют семантики по умолчанию в HTML, но требуют явного определения роли для вспомогательных технологий.
HTML предоставляет ограниченный набор семантических элементов, таких
как <button>, <input>,
<nav>, <header>,
<section>. Для элементов вроде
<div> или <span> семантика
отсутствует. Чтобы они корректно воспринимались скринридерами и другими
assistive-технологиями, необходимо задавать
ARIA-роль.
import { roles } from 'aria-query';
// Пример: создание кнопки из div
const divRole = roles.get('button');
console.log(divRole.isAbstract); // false
console.log(divRole.props); // { 'aria-pressed': undefined, ... }
Ключевое преимущество Aria-query — возможность программно получать список всех стандартных и нестандартных ролей, проверять их свойства и обязательные атрибуты.
Роли делятся на несколько категорий:
button,
checkbox, combobox) — интерактивные
элементы.article, main, navigation) —
структурные элементы страницы.banner,
contentinfo, complementary) — навигационные и
ориентирующие области.Для нестандартных элементов обычно применяются widget и landmark роли, поскольку они требуют явного указания поведения.
Каждая роль в Aria-query имеет свойства, которые позволяют:
Пример проверки роли:
import { roles } from 'aria-query';
function validateRole(element, roleName) {
const role = roles.get(roleName);
if (!role) throw new Error('Роль не найдена');
const requiredProps = Object.keys(role.requiredProps || {});
const missingProps = requiredProps.filter(prop => !element.hasAttribute(prop));
return missingProps.length === 0;
}
// Использование
const div = document.createElement('div');
div.setAttribute('role', 'button');
console.log(validateRole(div, 'button')); // true, если все обязательные props установлены
Для нестандартного элемента с ролью button необходимо не
только указать роль, но и добавить обработку событий, соответствующую
поведению:
const customButton = document.createElement('div');
customButton.setAttribute('role', 'button');
customButton.setAttribute('tabindex', '0');
customButton.addEventListener('click', () => {
console.log('Нажата кнопка');
});
customButton.addEventListener('keydown', (event) => {
if (event.key === 'Enter' || event.key === ' ') {
event.preventDefault();
customButton.click();
}
});
document.body.appendChild(customButton);
Здесь tabindex="0" делает элемент доступным для
фокусировки с клавиатуры, а обработка keydown обеспечивает
поведение, аналогичное нативной кнопке.
Aria-query позволяет определить, какие роли совместимы с какими элементами, чтобы избежать ошибок:
import { elementRoles } from 'aria-query';
const rolesForDiv = elementRoles.get('div');
console.log(Array.from(rolesForDiv)); // Set(…) ролей, разрешенных для <div>
Это особенно важно при разработке библиотек компонентов, где нестандартные элементы заменяют нативные, а пользователи ожидают корректной доступности.
Для сложных виджетов часто создаются кастомные компоненты с нестандартными элементами, но с ролями, полностью соответствующими спецификации ARIA. В этом случае Aria-query позволяет:
import { roles } from 'aria-query';
const sliderRole = roles.get('slider');
console.log(sliderRole.requiredProps); // { 'aria-valuemax': undefined, 'aria-valuemin': undefined, 'aria-valuenow': undefined }
const slider = document.createElement('div');
slider.setAttribute('role', 'slider');
slider.setAttribute('aria-valuemin', '0');
slider.setAttribute('aria-valuemax', '100');
slider.setAttribute('aria-valuenow', '50');
Использование Aria-query гарантирует соответствие спецификации ARIA и повышает совместимость с различными assistive-технологиями, включая экранные читалки и голосовое управление.
Некоторые роли являются абстрактными, и их нельзя назначать напрямую, но они описывают базовую функциональность, которую наследуют конкретные роли. Aria-query позволяет определить иерархию ролей, что важно для разработки сложных UI-компонентов:
import { roles } from 'aria-query';
const listRole = roles.get('list');
console.log(listRole.abstract); // true
const listboxRole = roles.get('listbox');
console.log(listboxRole.baseConcepts); // наследует свойства list
Это знание помогает правильно строить компоненты на основе
<div> и <span>, обеспечивая полную
доступность без использования нативных элементов.