Slim.js — это легковесный JavaScript-фреймворк для построения компонентов с декларативным синтаксисом. Интеграция с WAI-ARIA позволяет создавать доступные пользовательские интерфейсы, которые корректно воспринимаются вспомогательными технологиями: скринридерами, клавиатурной навигацией и другими инструментами доступности.
WAI-ARIA (Web Accessibility Initiative – Accessible Rich Internet Applications) — это набор атрибутов, которые описывают роль, состояние и свойства элементов интерфейса для повышения их доступности. В Slim.js эти атрибуты применяются напрямую к компонентам и их внутренним элементам через шаблоны и динамические привязки.
Каждый интерактивный элемент должен иметь соответствующую роль, чтобы скринридеры понимали его назначение.
import Slim from 'slim-js';
class ButtonComponent extends Slim {
get template() {
return `
<button role="button" @click="handleClick">
<slot></slot>
</button>
`;
}
handleClick() {
console.log('Button clicked');
}
}
customElements.define('button-component', ButtonComponent);
Ключевые моменты:
role="button" явно указывает, что элемент
интерактивен.WAI-ARIA предоставляет набор атрибутов aria-*,
позволяющих отслеживать состояние компонентов: активность, свёрнутость,
выделение.
class AccordionComponent extends Slim {
isOpen = false;
get template() {
return `
<div class="accordion">
<button
@click="toggle"
aria-expanded="${this.isOpen}"
aria-controls="panel1"
>
Заголовок аккордеона
</button>
<div id="panel1" aria-hidden="${!this.isOpen}">
Контент аккордеона
</div>
</div>
`;
}
toggle() {
this.isOpen = !this.isOpen;
this.update();
}
}
customElements.define('accordion-component', AccordionComponent);
Особенности:
aria-expanded отражает, открыт ли элемент.aria-hidden указывает, видим ли контент для
вспомогательных технологий.update().Для доступных компонентов важно управлять фокусом и обработкой клавиш.
class TabsComponent extends Slim {
activeTab = 0;
get template() {
return `
<div role="tablist">
<button
role="tab"
aria-selected="${this.activeTab === 0}"
tabindex="${this.activeTab === 0 ? 0 : -1}"
@keydown="handleKeydown(0, $event)"
@click="selectTab(0)"
>Вкладка 1</button>
<button
role="tab"
aria-selected="${this.activeTab === 1}"
tabindex="${this.activeTab === 1 ? 0 : -1}"
@keydown="handleKeydown(1, $event)"
@click="selectTab(1)"
>Вкладка 2</button>
<div role="tabpanel" aria-hidden="${this.activeTab !== 0}">Контент 1</div>
<div role="tabpanel" aria-hidden="${this.activeTab !== 1}">Контент 2</div>
</div>
`;
}
selectTab(index) {
this.activeTab = index;
this.update();
}
handleKeydown(index, event) {
if (event.key === 'ArrowRight') this.selectTab((index + 1) % 2);
if (event.key === 'ArrowLeft') this.selectTab((index + 2 - 1) % 2);
}
}
customElements.define('tabs-component', TabsComponent);
Особенности:
tabindex управляет фокусируемостью.aria-selected указывает выбранную вкладку.Некоторые элементы требуют правильной вложенности и связей:
aria-controls связывает управляющий элемент с
содержимым.aria-labelledby связывает элемент с его
заголовком.role="group" или role="list" помогают
определить семантику контейнера.<div role="list" aria-label="Список задач">
<div role="listitem">Задача 1</div>
<div role="listitem">Задача 2</div>
</div>
Slim.js позволяет создавать такие списки с динамическим контентом через циклы:
class TaskList extends Slim {
tasks = ['Задача 1', 'Задача 2'];
get template() {
return `
<div role="list" aria-label="Список задач">
${this.tasks.map(task => `<div role="listitem">${task}</div>`).join('')}
</div>
`;
}
}
customElements.define('task-list', TaskList);
Slim.js упрощает динамическое управление ARIA-атрибутами:
aria-*.update() автоматически
перерисовывает шаблон и обновляет атрибуты.class CheckboxComponent extends Slim {
checked = false;
get template() {
return `
<div role="checkbox"
aria-checked="${this.checked}"
tabindex="0"
@click="toggle"
@keydown.space.prevent="toggle">
${this.checked ? '☑' : '☐'} Выбрать
</div>
`;
}
toggle() {
this.checked = !this.checked;
this.update();
}
}
customElements.define('checkbox-component', CheckboxComponent);
Преимущества такого подхода:
aria-*.aria-controls,
aria-labelledby) создают логическую семантику
интерфейса.Slim.js и WAI-ARIA обеспечивают лёгкую интеграцию доступности в современные веб-компоненты без сложных обходных решений.