主要ルール紹介
JSX 環境でeslint-plugin-jsx-a11yを使うと、アクセシビリティの問題を事前に発見して改善できます。ここでは主要なルールと対処方法を紹介します。
1. 設定ガイド
インストール
yarn add -D eslint-plugin-jsx-a11y適用方法
.eslintrcまたはeslint.config.jsに次のように追加してください。
2. 主要ルールと対処法
alt-text
<img />には代替テキスト(alt)が必要です。情報を伝えない画像であってもalt属性自体は空でも必ず付け、画像の目的と文脈に合う内容にしましょう。
リンク内に画像だけがある場合
❌ 誤った例
<a href="/home">
<img src="home.svg" />
</a>✅ 正しい例
<a href="/home">
<img src="home.svg" alt="ホーム" />
</a>情報を伝えない画像
❌ 誤った例
<img src="divider.png" alt="区切り線" />✅ 正しい例
<img src="divider.png" alt="" />テキストと一緒のアイコン
❌ 誤った例
<button>
<img src="trash-icon.svg" alt="削除アイコン" />
削除
</button>✅ 正しい例
<button>
<img src="trash-icon.svg" alt="" />
削除
</button>control-has-associated-label
インタラクティブ要素(入力フィールド、ボタン、セレクトなど)には、目的をユーザーに明確に伝える名前が必須です。名前がない/不明確な要素は、スクリーンリーダー利用者や音声アシスタント利用者に大きな不便を与えます。詳しくはインタラクティブ要素に名前を付けるを参照してください。
eslint-plugin-jsx-allyの recommendedではこのルールは既定で無効なので、次のようにrulesに明示的に追加して有効化してください。
アイコンボタンにラベルがない場合
❌ 誤った例
<button>
<img src="close.svg" alt="" />
</button>✅ 正しい例
<button aria-label="閉じる">
<img src="close.svg" alt="" />
</button>
// または
<button>
<img src="close.svg" alt="閉じる" />
</button>no-noninteractive-element-interactions
非インタラクティブ要素(<div>、<span>など)にクリックハンドラーを付ける場合は、必ずroleなどでインタラクティブ要素であることを明示してください。
インタラクティブ要素の一覧
| 要素 | 条件 |
|---|---|
<a> | - |
<audio> | controls属性がある場合 |
<button> | - |
<details> | - |
<embed> | - |
<iframe> | - |
<img> | usemap属性がある場合 |
<input> | typeがHidden stateでない場合 |
<keygen> | - |
<label> | - |
<menu> | typeがtoolbar stateの場合 |
<object> | usemap属性がある場合 |
<select> | - |
<textarea> | - |
<video> | controls属性がある場合 |
なぜroleのない非インタラクティブ要素にクリックハンドラーを付けてはいけないの?
非インタラクティブ要素にクリックハンドラーだけを付けると、スクリーンリーダーなどの支援技術がその要素を正しく認識できず、スクリーンリーダー利用者やキーボード利用者を混乱させます。
❌ 誤った例
<div onClick={handleClick}>クリック</div>✅ 正しい例
<div role="button" tabIndex={0} onClick={handleClick}>
クリック
</div>no-noninteractive-element-to-interactive-role
<main>, <area>, <h1>, <h2>, <img>, <li>, <ul>, <ol>など意味のあるコンテナー要素に、buttonやlinkなどの**インタラクティブな役割(role)**を与えてはいけません。意味に合ったタグを使いましょう。
❌ 誤った例
<main role="button" onClick={handleClick}>保存</main>
<ul role="button" onClick={handleClick}>リスト</ul>
<img role="button" onClick={handleClick} src="foo.png" />✅ 正しい例
<button onClick={handleClick}>保存</button>
<a href="/list">リスト</a>no-noninteractive-tabindex
非インタラクティブ要素にtabIndexを付けると警告になります。tabIndexはインタラクティブ要素にのみ使いましょう。不要なら削除し、必要なら適切なロールやイベントを付けてください。
なぜインタラクティブ要素にだけtabIndexを付けるべき?
tabIndexはキーボード利用者がTabで要素間を移動する際に使う属性です。非インタラクティブ要素に付けると次の問題を招きます。
- スクリーンリーダー利用者が、その要素を操作可能と誤解する
- キーボード利用者が予期しない要素にフォーカスしてしまう
- DOM の自然なフォーカス順序が崩れる
したがってtabIndexは<button>、<a>、<input>、あるいは適切なroleを付け実際に操作可能な要素に限定して使いましょう。
❌ 誤った例
<div tabIndex={0}>テキスト</div>✅ 正しい例
<span>テキスト</span>
// または
<div tabIndex={0} role="button">ボタン</div>tabindex-no-positive
tabIndexに1以上の値を使うと、DOMの順序と異なるフォーカス移動になり、挙動の予測が難しくなります。0または-1のみを使いましょう。
❌ 誤った例
<button tabIndex={2}>確認</button>✅ 正しい例
<button tabIndex={0}>確認</button>さらに多くのルールと例は公式ドキュメントを参照してください: eslint-plugin-jsx-a11y