🔦

jsx-a11y 用 ESLint プラグインを導入する

eslint-plugin-jsx-a11y を導入する際に気を付けることを簡単に書かせていただいた。

By jiyuujin at

#A11Y
#React
#TypeScript
jsx-a11y 用 ESLint プラグインを導入するをはてなブックマークに追加

jsx-a11y 用 ESLint プラグインを導入する

当方 Create-React-App (CRA) のプロジェクトにおけるアクセシビリティを考慮するため、jsx-a11y 用 ESLint プラグイン eslint-plugin-jsx-a11y をインストールすることにしました。

# npm
npm i -D eslint-plugin-jsx-a11y

# yarn
yarn add -D eslint-plugin-jsx-a11y

実際に導入する

下記のように .eslintrc.jsextendsplugins に設定します。

module.exports = {
  extends: ['plugin:jsx-a11y/recommended'],
  plugins: ['jsx-a11y'],
}

ルールセット

ルールセットは 2 種類あります。

  • jsx-a11y/recommended
  • jsx-a11y/strict

基本的にどちらのルールセットを使っても構わない。

対応ルール全てエラーと認識してくれる一方、一部ルールではエラーと見做さないケースも設定できたりなど、弾力的に運用できます。

まず、マウスやキーイベントのリスナーなどに role を付けます。

該当のルールは下記の通りとなります。

次に、非対話型の HTML 要素や WAI-ARIA ロールはマウスやキーイベントのハンドラーをサポートしないので role を付ける。

:::message is-primary

非対話型の HTML 要素

<main><area><h1><h2><h3><h4><h5><h6><p><img><li><ul><ol>

非対話型の WAI-ARIA ロール

<article><banner><complementary><img><listitem><main><region><tooltip>

:::

該当のルールは下記の通りになります。

最後に th 要素のみ scope を許容します。

該当のルールは scope です。

あらゆる warning を解決する

eslint-plugin-jsx-a11y  を読み込んで eslint --fix してみます。

# eslint
npx eslint . --ext ts,tsx --fix

修正すべき warning に遭遇しなければ、導入完了とみて問題無いだろう。しかし、いくつかの warning に遭遇することがあります。

具体的には div などに代表される静的な HTML 要素で onClick イベントを使ってしまっているケースなどが挙げられます。

jsx-a11y/click-events-have-key-events

onClick イベントを使う場合、マウスを使用できないユーザのために onKeyUp / onKeyDown / onKeyPress を考慮する必要があります。

もちろん 1 つも無ければ、アクセシビリティ的なアウトになります。

const Component = () => <div onClick={() => {}}>{/* 何らかのコンテンツ */}</div>

なお、広くボタン用途に使われる button 要素で onClick イベントを使用した方が良いと考えています。

この button 要素では既に onKeyUp / onKeyDown / onKeyPress が考慮されています。

const Component = () => <button onClick={() => {}}>{/* 何らかのコンテンツ */}</button>

jsx-a11y/no-static-element-interactions

div など静的な HTML 要素でマウスやキーイベントを設定する場合に、要素の role 属性を設定する必要があります。

const Component = () => (
  <div onClick={() => {}} role="button">
    {/* 何らかのコンテンツ */}
  </div>
)

onClick イベントと合わせて role 属性を設定しても特に問題はありません。

ただし、広くボタン用途で使われる button 要素に変更する選択肢を取った方が良いと考えています。

const Component = () => <button onClick={() => {}}>{/* 何らかのコンテンツ */}</button>

最後に

とあるプロジェクトで ESLint プラグインを設定した当初 70 近い warning を観測しました。

68 problems (68 errors, 0 warnings)

Errors:
  29  jsx-a11y/click-events-have-key-events
  28  jsx-a11y/no-static-element-interactions
   5  jsx-a11y/aria-role
   2  jsx-a11y/media-has-caption
   2  jsx-a11y/anchor-is-valid
   1  jsx-a11y/no-autofocus
   1  jsx-a11y/no-noninteractive-element-interactions

しかし、そのどれもが同じようなエラーのため、そこまで怖がる必要はありません。

アクセシビリティの ESLint に伴う --fix をビルド時に強制したことで、最低限の品質を担保させるようにしました。

その他

eslint-plugin-jsx-a11y でサポートされているルール一覧になります。

視覚によるチェックでは確認しきれない部分を補うため、コードベースでコンポーネントごとに自動チェックします。

Rule Recommended Strict
alt-text error error
anchor-has-content error error
anchor-is-valid error error
aria-activedescendant-has-tabindex error error
aria-props error error
aria-proptypes error error
aria-role error error
aria-unsupported-elements error error
autocomplete-valid error error
click-events-have-key-events error error
heading-has-content error error
html-has-lang error error
iframe-has-title error error
img-redundant-alt error error
interactive-supports-focus error error
label-has-associated-control error error
media-has-caption error error
mouse-events-have-key-events error error
no-access-key error error
no-autofocus error error
no-distracting-elements error error
no-interactive-element-to-noninteractive-role error, with options error
no-noninteractive-element-interactions error, with options error
no-noninteractive-element-to-interactive-role error, with options error
no-noninteractive-tabindex error, with options error
no-onchange error error
no-redundant-roles error error
no-static-element-interactions error, with options error
role-has-required-aria-props error error
role-supports-aria-props error error
scope error, with options error
tabindex-no-positive error error

<!--

eslint-plugin-vuejs-accessibility

eslint-plugin-vuejs-accessibility でサポートされているルール一覧です。

視覚によるチェックでは確認しきれない部分を補うため、コードベースでコンポーネントごとに自動チェックする。

Rule Recommended
accessible-emoji error
alt-text error
anchor-has-content error
aria-props error
aria-role error
aria-unsupported-elements error
click-events-have-key-events error
form-control-has-label error
heading-has-content error
iframe-has-title error
interactive-supports-focus error
label-has-for error
media-has-caption error
mouse-events-have-key-events error
no-access-key error
no-autofocus error
no-distracting-elements error
no-onchange error
no-redundant-roles error
role-has-required-aria-props error
tabindex-no-positive error
-->
jsx-a11y 用 ESLint プラグインを導入するをはてなブックマークに追加