Плагин eslint-plugin-jsx-a11y

eslint-plugin-jsx-a11y представляет собой специализированный плагин для ESLint, ориентированный на анализ JSX-разметки с точки зрения доступности (accessibility, a11y). Основная задача — выявление нарушений практик, затрудняющих использование интерфейса людьми с ограниченными возможностями, включая пользователей экранных читалок, клавиатурной навигации и вспомогательных технологий.

Плагин работает статически, анализируя JSX-деревья и проверяя соответствие набору правил, основанных на рекомендациях WAI-ARIA и стандартах WCAG.

Установка и подключение

Плагин устанавливается как зависимость проекта и подключается в конфигурации ESLint.

npm install eslint-plugin-jsx-a11y --save-dev

или

yarn add eslint-plugin-jsx-a11y -D

Подключение в конфигурации ESLint:

{
  "plugins": ["jsx-a11y"]
}

Использование рекомендуемого набора правил:

{
  "extends": ["plugin:jsx-a11y/recommended"]
}

Дополнительно возможен строгий режим:

{
  "extends": ["plugin:jsx-a11y/strict"]
}

Базовая архитектура проверок

Плагин анализирует:

  • JSX-элементы React
  • Атрибуты HTML-элементов внутри JSX
  • ARIA-атрибуты
  • Взаимосвязь между интерактивностью и семантикой
  • Навигационные свойства (tabIndex, role)

Проверки реализованы как набор независимых правил, каждое из которых отвечает за узкий аспект доступности.

Категории правил

Правила плагина условно делятся на группы:

Семантика и структура

Контроль корректного использования HTML-элементов:

  • заголовки
  • ссылки
  • списки
  • интерактивные элементы

ARIA-атрибуты

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

  • допустимость атрибутов
  • соответствие ролей
  • обязательные свойства

Навигация с клавиатуры

Контроль доступности интерактивных элементов:

  • tabIndex
  • обработчики событий клавиатуры
  • фокусируемость

Медиа и альтернативный контент

  • alt для изображений
  • текстовые альтернативы

Ключевые правила плагина

alt-текст для изображений

Правило: jsx-a11y/alt-text

Контролирует наличие и корректность alt-атрибута.

Некорректный пример:

<img src="photo.jpg" />

Корректный пример:

<img src="photo.jpg" alt="Описание изображения" />

Особые случаи включают декоративные изображения:

<img src="decorative.png" alt="" />

ARIA-атрибуты

Правило: jsx-a11y/aria-props

Контролирует допустимость ARIA-атрибутов в JSX.

Некорректный пример:

<div aria-unknown="true" />

Корректный пример:

<div aria-hidden="true" />

Также проверяется соответствие типов значений:

<button aria-expanded="not-a-boolean" />

Обязательные ARIA-свойства

Правило: jsx-a11y/role-has-required-aria-props

Некоторые роли требуют обязательных атрибутов.

Пример нарушения:

<div role="checkbox" />

Корректно:

<div role="checkbox" aria-checked="false" />

Интерактивность и фокус

Правило: jsx-a11y/interactive-supports-focus

Интерактивные элементы должны быть доступны через клавиатуру.

Нарушение:

<div onCl ick={handleClick} />

Корректный вариант:

<div onCl ick={handleClick} tabIndex={0} />

или семантически правильнее:

<button onCl ick={handleClick} />

Некорректные обработчики событий

Правило: jsx-a11y/click-events-have-key-events

Обеспечивает поддержку клавиатурных событий для кликабельных элементов.

Нарушение:

<div onCl ick={handleClick} />

Корректно:

<div onCl ick={handleClick} onKeyD own={handleKeyDown} />

Неподдерживаемые интерактивные элементы

Правило: jsx-a11y/no-static-element-interactions

Запрещает использование статических элементов как интерактивных без корректной семантики.

Нарушение:

<span onCl ick={handleClick}>Кнопка</span>

Корректно:

<button onCl ick={handleClick}>Кнопка</button>

Label и формы

Правило: jsx-a11y/label-has-associated-control

Контролирует связь label и input.

Нарушение:

<label>Имя</label>
<input type="text" />

Корректно:

<label htmlFor="name">Имя</label>
<input id="name" type="text" />

Альтернативный вариант:

<label>
  Имя
  <input type="text" />
</label>

Ссылки и контент

Правило: jsx-a11y/anchor-has-content

Ссылка должна содержать текст или доступное содержимое.

Нарушение:

<a href="/home"></a>

Корректно:

<a href="/home">Главная</a>

Заголовки

Правило: jsx-a11y/heading-has-content

Контролирует наличие содержимого в заголовках.

Нарушение:

<h1 />

Корректно:

<h1>Заголовок</h1>

Управление фокусом

Правило: jsx-a11y/no-autofocus

Ограничивает использование autoFocus, так как оно может нарушать пользовательский поток.

Нарушение:

<input autoFocus />

Включение допускается только при явной необходимости интерфейса.

tabIndex и порядок навигации

Правило: jsx-a11y/tabindex-no-positive

Запрещает положительные значения tabIndex.

Нарушение:

<div tabIndex={5} />

Корректно:

<div tabIndex={0} />

или удаление tabIndex для естественного порядка.

Конфигурация правил

Каждое правило может быть переопределено:

{
  "rules": {
    "jsx-a11y/alt-text": "error",
    "jsx-a11y/no-autofocus": "warn",
    "jsx-a11y/click-events-have-key-events": "error"
  }
}

Возможные уровни:

  • off
  • warn
  • error

Отключение правил в коде

Локальное отключение:

// eslint-disable-next-line jsx-a11y/alt-text
<img src="image.jpg" />

Или для блока:

/* eslint-disable jsx-a11y/no-autofocus */
<input autoFocus />
/* eslint-enable jsx-a11y/no-autofocus */

Интеграция с React-проектами

В React-приложениях плагин часто подключается через preset:

{
  "extends": [
    "eslint:recommended",
    "plugin:react/recommended",
    "plugin:jsx-a11y/recommended"
  ]
}

В Next.js конфигурациях плагин используется как часть общего ESLint-набора фреймворка, дополняя проверки React и TypeScript.

Типовые конфликты и тонкая настройка

В реальных проектах возникают ситуации, требующие адаптации правил:

Сторонние UI-библиотеки

Компоненты могут не соответствовать требованиям a11y, что приводит к ложным срабатываниям.

Кастомные интерактивные элементы

При создании нестандартных компонентов требуется ручное управление ARIA-атрибутами.

SSR и гидратация

Некоторые правила могут конфликтовать с динамической генерацией DOM.

Поведенческие паттерны правил

Плагин ориентируется на следующие принципы:

  • семантическая корректность важнее визуального сходства
  • интерактивность должна быть явной
  • ARIA используется только при необходимости
  • нативные элементы предпочтительнее кастомных решений

Проверка составных компонентов

Особое внимание уделяется React-компонентам, которые инкапсулируют DOM:

const Button = ({ onClick }) => (
  <div onCl ick={onClick}>Click</div>
);

Такой код нарушает несколько правил одновременно:

  • отсутствие семантики
  • отсутствие клавиатурной доступности
  • отсутствие роли элемента

Корректная реализация:

const Button = ({ onClick }) => (
  <button onCl ick={onClick}>Click</button>
);