はじめに
この記事では、ESLint の Flat Config にアクセシビリティ向けルールのプラグインである eslint-plugin-jsx-a11y
を追加する手順について記載します。
開発環境
開発環境は以下の通りです。
- Windows 11
- VSCode
- TypeScript 5.2.2
- React 18.3.1
- Vite 5.3.1
- Node.js 20.15.0
- npm 10.8.1
- ESLint 8.57.0
- Prettier 3.3.2
- @eslint/js 9.6.0
- eslint-config-prettier 9.1.0
- eslint-plugin-jsx-a11y 6.9.0
- eslint-plugin-react 7.34.3
- globals 15.8.0
- typescript-eslint 7.15.0
事前準備
プロジェクトに ESLint のインストール・設定をしておきます。
React / TypeScript 環境における詳細手順はこちら。
Prettier を追加する手順はこちら。
eslint-plugin-jsx-a11y
のインストール
eslint-plugin-jsx-a11y
をインストールします。
npm install eslint-plugin-jsx-a11y --save-dev
一括設定
eslint.config.js
で eslint-plugin-jsx-a11y
をインポートして jsxA11y.flatConfigs.recommended
を追加します。
eslint.config.js
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginReactConfig from "eslint-plugin-react/configs/recommended.js";
import pluginReactJSXRuntime from "eslint-plugin-react/configs/jsx-runtime.js";
import jsxA11y from "eslint-plugin-jsx-a11y"; // Add
import eslintConfigPrettier from "eslint-config-prettier";
export default [
{
files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
settings: {
react: {
version: "detect",
},
},
},
{ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
pluginReactConfig,
pluginReactJSXRuntime,
jsxA11y.flatConfigs.recommended, // Add
eslintConfigPrettier,
];
動作確認
img
タグの alt
がない状態で、ESLint を実行してみます。
App.tsx
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";
function App() {
const [count, setCount] = useState(0);
return (
<>
<div>
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
{/* alt を削除 */}
<img src={viteLogo} className="logo" />
</a>
<a href="https://react.dev" target="_blank" rel="noreferrer">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
以下のエラーが表示されます。
13:11 error img elements must have an alt prop, either with meaningful text, or an empty string for decorative images
jsx-a11y/alt-text
alt
を追加するとエラーが消えます。
App.tsx
import { useState } from "react";
import reactLogo from "./assets/react.svg";
import viteLogo from "/vite.svg";
import "./App.css";
function App() {
const [count, setCount] = useState(0);
return (
<>
<div>
<a href="https://vitejs.dev" target="_blank" rel="noreferrer">
{/* alt を追加 */}
<img src={viteLogo} className="logo" alt="Vite logo" />
</a>
<a href="https://react.dev" target="_blank" rel="noreferrer">
<img src={reactLogo} className="logo react" alt="React logo" />
</a>
</div>
<h1>Vite + React</h1>
<div className="card">
<button onClick={() => setCount((count) => count + 1)}>
count is {count}
</button>
<p>
Edit <code>src/App.tsx</code> and save to test HMR
</p>
</div>
<p className="read-the-docs">
Click on the Vite and React logos to learn more
</p>
</>
);
}
export default App;
個別設定
eslint-plugin-jsx-a11y
の各ルールを個別に設定することもできます。
-
pugins
に"jsx-a11y": jsxA11y
を追加 -
rules
に"jsx-a11y/alt-text": "error"
を追加
eslint.config.js
import globals from "globals";
import pluginJs from "@eslint/js";
import tseslint from "typescript-eslint";
import pluginReactConfig from "eslint-plugin-react/configs/recommended.js";
import pluginReactJSXRuntime from "eslint-plugin-react/configs/jsx-runtime.js";
import jsxA11y from "eslint-plugin-jsx-a11y";
import eslintConfigPrettier from "eslint-config-prettier";
export default [
{
files: ["**/*.{js,mjs,cjs,ts,jsx,tsx}"],
settings: {
react: {
version: "detect",
},
},
plugins: {
"jsx-a11y": jsxA11y, // Add
},
rules: {
"jsx-a11y/alt-text": "error", // Add
},
},
{ languageOptions: { parserOptions: { ecmaFeatures: { jsx: true } } } },
{ languageOptions: { globals: globals.browser } },
pluginJs.configs.recommended,
...tseslint.configs.recommended,
pluginReactConfig,
pluginReactJSXRuntime,
eslintConfigPrettier,
];
参考
関連記事