eslint-plugin-jsx-a11y を使ってアクセシビリティ改善

# はじめに
この記事では、アクセシビリティをチェックする ESLint のプラグインである **eslint-plugin-jsx-a11y** の設定方法と各ルールの概要を実際にコードを書きながら確認していきます。
（たくさんルールがあるので、随時更新・補足していきます。）

https://github.com/jsx-eslint/eslint-plugin-jsx-a11y

# 開発環境
開発環境は以下の通りです。
- Windows11
- eslint-plugin-jsx-a11y 6.8.0
- ESLint 8.57.0
- npm 10.5.2
- Node.js 20.13.1
- TypeScript 5.4.2
- React 18.2.0

# インストールと設定
まずは以下のコマンドで ESLint と eslint-plugin-jsx-a11y をインストールします。

```powershell
npm install eslint --save-dev
```

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

次に ```.eslintrc.json``` の ```extends``` に ```plugin:jsx-a11y/strict``` を追加します。

```.eslintrc.json
{
  "extends": ["plugin:jsx-a11y/strict"]
}
```

これで eslint-plugin-jsx-a11y が有効になります。

:::note
```strict``` と ```recommended``` の差異については、[Supported Rules](/strict) に記載があります。
ただ、2024年5月現在、[anchor-ambiguous-text](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-ambiguous-text.md) というルールが```strict``` では有効、```recommended``` では無効という違いしかありません。
:::

:::note
各ルールの設定内容のカスタマイズやルールを適用するコンポーネントの指定、独自のルールの追加などもできます。
:::

# ルール
インストールと設定が完了したので、各ルールの動作確認をしていきます。
各ルールは全てデフォルト状態です。

## [```alt-text```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/alt-text.md)
以下のタグで alt 属性が抜けている場合、エラーになります。

- ```<img>```
- ```<area>```
- ```<input type="image">```
- ```<object>```


エラーメッセージは以下の通りです。

```img elements must have an alt prop, either with meaningful text, or an empty string for decorative images.```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/c90a3572-cc74-d14c-1c9a-e104dcf21f95.png)

alt 属性を追加すると、エラーが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/857fc488-bdc6-1f8d-c3c0-2c2f91db6783.png)

## [```anchor-has-content```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-has-content.md)
a タグ内に値がない場合、エラーになります。

```Anchors must have content and the content must be accessible by a screen reader.```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/61bcc47b-a82f-96dd-775b-53b89b477f82.png)

値を追加すると、エラーが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/da8ef2ed-1233-cddf-ffd0-740118c13cf5.png)

## [```anchor-is-valid```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/anchor-is-valid.md)
a タグに有効な href 属性がない場合、エラーになります。

```The href attribute is required for an anchor to be keyboard accessible. Provide a valid, navigable address as the href value. If you cannot provide an href, but still need the element to resemble a link, use a button and change it with appropriate styles. Learn more: https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/HEAD/docs/rules/anchor-is-valid.md```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/09261eed-9894-3306-2bf9-b3086c85d22d.png)

有効な href 属性を追加すると、エラーが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/68421db5-96e4-9050-8559-42871032d88b.png)

## [```aria-activedescendant-has-tabindex```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-activedescendant-has-tabindex.md)
[aria-activedescendant](https://developer.mozilla.org/en-US/docs/web/Accessibility/ARIA/Attributes/aria-activedescendant) 属性を含むタグに tabindex 属性がない場合、エラーになります。

```An element that manages focus with `aria-activedescendant` must have a tabindex```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/078992c4-238e-9675-e629-b04246765c50.png)

tabindex 属性を追加すると、エラーが消えます。
※他のルール（```no-noninteractive-tabindex```）で、tabindex 属性に別のエラーが表示されています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/fe799b76-a04e-5484-7c4c-52a32a94e700.png)


## [```aria-props```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-props.md)
[WAI-ARIA States and Properties](https://www.w3.org/TR/wai-aria/#introstates) に記載がない aria-* 属性を利用すると、エラーが表示されます。

```aria-labeledby: This attribute is an invalid ARIA attribute. Did you mean to use aria-labelledby?```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/994bc862-401b-d505-97ac-e0a656d36969.png)

記載がある aria-* 属性を利用すると、エラーが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/05d50ad6-2cb6-c9d2-6ee0-e3827f5bcf02.png)

## [```aria-proptypes```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-proptypes.md)
aria-proptypes 属性に boolean 以外の値の場合、エラーが表示されます。

```The value for aria-hidden must be a boolean.```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/3590e185-4feb-88ce-b442-1d73f88bb6c5.png)

boolean にすると、エラーが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/10e79195-2259-7d24-736b-954d328ad732.png)

## [```aria-role```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/aria-role.md)
[WAI-ARIA](https://www.w3.org/TR/wai-aria/#role_definitions) に記載がない ARIA role を利用すると、エラーが表示されます。

```Elements with ARIA roles must use a valid, non-abstract ARIA role.```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/182a6702-5e04-3783-7d7d-02740d1490d1.png)

記載がある ARIA role を利用すると、エラーが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/92108c8c-65b4-d51d-91ff-ae5e38102263.png)

## [```aria-unsupported-elements```]()
```meta```, ```html```, ```script```, ```style``` など ARIA Role をサポートしていないタグで ARIA Role を利用すると、エラーが表示されます。

```This element does not support ARIA roles, states and properties. Try removing the prop 'role'.```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/bbe0789e-fb01-6c8c-3e93-968ed630c4dc.png)

## [```autocomplete-valid```](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/main/docs/rules/autocomplete-valid.md)
autocomplete 属性がフォームに適した値となっていない場合、エラーが表示されます。

```the autocomplete attribute is incorrectly formatted```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/87fcfa94-5f60-7b88-29e7-1b86c84797f0.png)

適した値になると、エラーが消えます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/318188/ded458ad-f57e-f56e-0f1d-6d2cfead2497.png)


# 参考
- [eslint-plugin-jsx-a11y](https://github.com/jsx-eslint/eslint-plugin-jsx-a11y)